home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 23 / AMIGAplus Sonderheft 23 (2000)(Falke)(DE)[!].iso / Updates / AddOns / WormWars / Source / engine.c < prev    next >
C/C++ Source or Header  |  1999-11-08  |  109KB  |  3,371 lines

  1. /* $Filename:       WormWars/Source/engine.c(pp) $
  2.  * $VER:            WormWars 4.1 (6.6.99) $
  3.  * $Description:    Common game engine components $
  4.  *
  5.  * © Copyright 1999 James R. Jacobs.
  6.  * Freely distributable.
  7.  *
  8.  * Prerelease version.
  9.  */
  10.  
  11. #include "stdafx.h"
  12. #include "diff.h"
  13. #include "same.h"
  14. #include "engine.h"
  15.  
  16. // PRIVATE STRUCTURES -----------------------------------------------------
  17.  
  18. struct
  19. {    SBYTE        x, y, oldx, oldy;
  20.     BOOL        alive, moved, teleported, visible;
  21. } bullet[POWERLIMIT + 1];
  22. struct
  23. {    SBYTE        x, y, deltax, deltay, last;
  24.     BOOL        alive, moved;
  25. } frag[ORBS + 2][8];
  26. struct
  27. {    SBYTE        x, y, last;
  28.     BOOL        alive;
  29. } killer[KILLERS + 1];
  30. struct
  31. {   SBYTE       x, y, deltax, deltay;
  32.     BOOL        alive, moved;
  33.     ULONG       receipt;
  34. } missile[4];
  35.  
  36. struct
  37. {    WORD        frequency;
  38.     LONG        score;
  39. } object[LASTOBJECT + 1] =
  40. {    {1280,  60},    //    AFFIXER
  41.     {  80,  20},    //  AMMO
  42.     { 110,  20},    //    ARMOUR
  43.     { 240,  50},    //    BIAS
  44.     { 200,  30},    //    BOMB
  45.     {  80,  10},    //    BONUS
  46.     { 360,  50},    //    GROWER
  47.     {1360,  60},    //    ICE
  48.     { 150,  50},    //    LIFE
  49.     { 240,  40},    //    MISSILE
  50.     { 640,  50},    //    MULTIPLIER
  51.     { 400,  10},    //    NITRO
  52.     { 240,  30},    //    POWER
  53.     { 480,  50},    //    PROTECTOR
  54.     { 600,  40},    //    SLAYER
  55.     { 730,  70},    //    SWITCHER
  56.     {1900,    90},    //    HEALER
  57.     { 320,  20},    //    TONGUE
  58.     {2700, 100        //    TREASURE
  59. }    };
  60.  
  61. /*    -200        common
  62.     220-400        uncommon
  63.     420-980        rare
  64.     1000+        very rare    */
  65.  
  66. struct
  67. {   SBYTE        x, y, deltax, deltay, relx, rely;
  68.     BOOL        alive, last, visible;
  69. } protector[4][PROTECTORS + 1];
  70. struct
  71. {    SBYTE        x, y, time;
  72.     BOOL        alive;
  73. } timebomb[TIMEBOMBS + 1];
  74. struct
  75. {    SBYTE        deltax;
  76.     SBYTE        deltay;
  77. } thequeue[4][QUEUELIMIT + 1];
  78.  
  79. SBYTE eachworm[4][2][9] =
  80. {    {    {    GREENHEADUP,        GREENHEADUP,        GREENHEADUP,
  81.             GREENHEADLEFT,        ANYTHING,            GREENHEADRIGHT,
  82.             GREENHEADDOWN,        GREENHEADDOWN,        GREENHEADDOWN
  83.         },
  84.         {    GREENMODEUP,        GREENMODEUP,        GREENMODEUP,
  85.             GREENMODELEFT,        ANYTHING,            GREENMODERIGHT,
  86.             GREENMODEDOWN,        GREENMODEDOWN,        GREENMODEDOWN
  87.     }    },
  88.     {    {    REDHEADUP,            REDHEADUP,            REDHEADUP,
  89.             REDHEADLEFT,        ANYTHING,            REDHEADRIGHT,
  90.             REDHEADDOWN,        REDHEADDOWN,        REDHEADDOWN
  91.         },
  92.         {    REDMODEUP,            REDMODEUP,            REDMODEUP,
  93.             REDMODELEFT,        ANYTHING,            REDMODERIGHT,
  94.             REDMODEDOWN,        REDMODEDOWN,        REDMODEDOWN
  95.     }    },
  96.     {    {    BLUEHEADUP,            BLUEHEADUP,            BLUEHEADUP,
  97.             BLUEHEADLEFT,        ANYTHING,            BLUEHEADRIGHT,
  98.             BLUEHEADDOWN,        BLUEHEADDOWN,        BLUEHEADDOWN
  99.         },
  100.         {    BLUEMODEUP,            BLUEMODEUP,            BLUEMODEUP,
  101.             BLUEMODELEFT,        ANYTHING,            BLUEMODERIGHT,
  102.             BLUEMODEDOWN,        BLUEMODEDOWN,        BLUEMODEDOWN
  103.     }    },
  104.     {    {    YELLOWHEADUP,        YELLOWHEADUP,        YELLOWHEADUP,
  105.             YELLOWHEADLEFT,        ANYTHING,            YELLOWHEADRIGHT,
  106.             YELLOWHEADDOWN,        YELLOWHEADDOWN,        YELLOWHEADDOWN
  107.         },
  108.         {    YELLOWMODEUP,        YELLOWMODEUP,        YELLOWMODEUP,
  109.             YELLOWMODELEFT,        ANYTHING,            YELLOWMODERIGHT,
  110.             YELLOWMODEDOWN,        YELLOWMODEDOWN,        YELLOWMODEDOWN
  111. }    }    };
  112.  
  113. // MODULE VARIABLES (used only within engine.c(pp)) -----------------------
  114.  
  115. MODULE    ABOOL                    ignorenextjoy,
  116.                                 letters[4][LETTERS + 1], trainer;
  117. MODULE    SBYTE                    fragspeed, ice, killerspeed, noletter,
  118.                                 orbspeed, outoftime, treasurer;
  119. MODULE    SWORD                    killerfreq, orbfreq, slimefreq,
  120.                                 slimegrowfreq;
  121.  
  122. // GLOBAL VARIABLES (owned by engine.c(pp), imported by system.c(pp)) -----
  123.  
  124. AGLOBAL    ABOOL                    clearthem    = FALSE,
  125.                                 modified    = FALSE;
  126. AGLOBAL    SBYTE                    a = GAMEOVER,
  127.                                 board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  128.                                 brush = STONE,
  129.                                 field[FIELDX + 1][FIELDY + 1], hi = 3,
  130.                                 level = 1, levels, lo = 0, reallevel,
  131.                                 startx[MAXLEVELS + 1],
  132.                                 starty[MAXLEVELS + 1];
  133. AGLOBAL    SWORD                    secondsleft, secondsperlevel;
  134. AGLOBAL    STRPTR                    pathname = (STRPTR) DEFAULTSET;
  135. AGLOBAL    ULONG                    delay, r;
  136. AGLOBAL    struct HiScoreStruct    hiscore[HISCORES + 1];
  137. AGLOBAL    struct OrbStruct        orb[ORBS + 1];
  138. AGLOBAL    struct TeleportStruct    teleport[MAXLEVELS + 1][4];
  139. AGLOBAL    struct WormStruct        worm[4];
  140.  
  141. /* FUNCTIONS --------------------------------------------------------------
  142.  
  143. NAME        align -- right-justify a string within another string
  144. SYNOPSIS    align(SBYTE, SBYTE, TEXT);
  145. FUNCTION    Moves all text in a string to the right, padding with
  146.             spaces. Does not itself add a null terminator.
  147. INPUTS      string - pointer to the string of text
  148.               size - size in characters of the containing string
  149.             filler - what to pad the left of the string with
  150. NOTE        Null terminators are written over by thissy function, but that
  151.             does not matter, because calling functions use Text() with an
  152.             explicit length. This function only works with monospaced
  153.             fonts.
  154. MODULE      engine.c */
  155.  
  156. void align(STRPTR string, SBYTE size, TEXT filler)
  157. {   SBYTE i, shift, length;
  158.  
  159.     length = strlen((const char*) string);
  160.     shift = size - length;
  161.     for (i = 1; i <= length; i++)
  162.         *(string + size - i) = *(string + size - i - shift);
  163.     for (i = 0; i <= shift - 1; i++)
  164.         *(string + i) = filler;
  165. }
  166.  
  167. ABOOL blocked(SBYTE which, SBYTE deltax, SBYTE deltay)
  168. {   if (field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)] < STONE
  169.     || field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)] > KILLER)
  170.         return(FALSE);
  171.     else return(TRUE);
  172. }
  173.  
  174. void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
  175. {    SBYTE    counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
  176.     LONG    score = 0L;
  177.  
  178.     effect(FXBOMBBLAST);
  179.  
  180.     strength = BOMBADD + (rand() % BOMBRAND);
  181.  
  182.     leftxmax = centrex - strength;
  183.     if (leftxmax < 0)
  184.         leftxmax = 0;
  185.     rightxmax = centrex + strength;
  186.     if (rightxmax > FIELDX)
  187.         rightxmax = FIELDX;
  188.     uppymax = centrey - strength;
  189.     if (uppymax < 0)
  190.         uppymax = 0;
  191.     downymax = centrey + strength;
  192.     if (downymax > FIELDY)
  193.         downymax = FIELDY;
  194.  
  195.     leftx = centrex;
  196.     rightx = centrex;
  197.     uppy = centrey;
  198.     downy = centrey;
  199.     for (counter = 1; counter <= strength; counter++)
  200.     {    if (leftx > leftxmax)
  201.         {    leftx--;
  202.             for (y = uppy; y <= downy; y++)
  203.                 score += squareblast(triggerer, player, field[leftx][y], leftx, y);
  204.         }
  205.         if (rightx < rightxmax)
  206.         {    rightx++;
  207.             for (y = uppy; y <= downy; y++)
  208.                 score += squareblast(triggerer, player, field[rightx][y], rightx, y);
  209.         }
  210.         if (uppy > uppymax)
  211.         {    uppy--;
  212.             for (x = leftx; x <= rightx; x++)
  213.                 score += squareblast(triggerer, player, field[x][uppy], x, uppy);
  214.         }
  215.         if (downy < downymax)
  216.         {    downy++;
  217.             for (x = leftx; x <= rightx; x++)
  218.                 score += squareblast(triggerer, player, field[x][downy], x, downy);
  219.     }    }
  220.  
  221.     if (triggerer == HEAD)
  222.     {    wormscore(player, score);
  223.         if (worm[player].bias)
  224.             stat(player, LIVESLINE);
  225.     } else
  226.         orb[player].score += score * orb[player].multi;
  227. }
  228.  
  229. void bouncekiller(SBYTE which, SBYTE x, SBYTE y)
  230. {    SBYTE i;
  231.  
  232.     if (field[x][y] == KILLER)
  233.         for (i = 0; i <= KILLERS; i++)
  234.             if (killer[i].alive && x == killer[i].x && y == killer[i].y)
  235.             {    killer[i].alive = FALSE;
  236.                 draw(x, y, BONUS);
  237.                 field[x][y] = BONUS;
  238.                 orb[which].score += KILLKILLER * orb[which].multi;
  239. }            }
  240.  
  241. ABOOL bounceorb(SBYTE which, SBYTE x, SBYTE y)
  242. {    if (orb[which].mode == NONE)
  243.     {    if (field[x][y] >= FIRSTNONE && field[x][y] <= LASTNONE)
  244.             return(TRUE);
  245.         else return(FALSE);
  246.     } else if (orb[which].mode == TONGUE)
  247.     {    if (field[x][y] >= FIRSTTONGUE && field[x][y] <= LASTTONGUE)
  248.             return(TRUE);
  249.         else return(FALSE);
  250.     } else // assumes orb[which].mode == ARMOUR
  251.     {    if (field[x][y] >= FIRSTARMOUR && field[x][y] <= LASTARMOUR)
  252.             return(TRUE);
  253.         else return(FALSE);
  254. }    }
  255.  
  256. SBYTE bsign(SBYTE value)
  257. {    if (value < 0)
  258.         return (-1);
  259.     else if (value > 0)
  260.         return (1);
  261.     else
  262.         return (0);
  263. }
  264.  
  265. void changefield(void)
  266. {   SBYTE x, y;
  267.  
  268.     for (x = 0; x <= FIELDX; x++)
  269.         for (y = 0; y <= FIELDY; y++)
  270.             field[x][y] = board[level][x][y];
  271. }
  272.  
  273. void clearhiscores(void)
  274. {    SBYTE i;
  275.     
  276.     clearthem = FALSE;
  277.     for (i = 0; i <= HISCORES; i++)
  278.     {    hiscore[i].player = -1;
  279.         hiscore[i].level = 0;
  280.         hiscore[i].score = 0L;
  281.         hiscore[i].name[0] = 0;
  282.         hiscore[i].fresh = FALSE;
  283. }   }
  284.  
  285. void clearletters(void)
  286. {    SBYTE player, which;
  287.  
  288.     for (player = 0; player <= 3; player++)
  289.         for (which = 0; which <= LETTERS; which++)
  290.         {    letters[player][which] = FALSE;
  291.             drawletter(player, FIRSTLETTER + which, BLACK);
  292. }        }
  293.  
  294. void copyfield(SBYTE source, SBYTE destination)
  295. {    SBYTE which, x, y;
  296.  
  297.     for (x = 0; x <= FIELDX; x++)
  298.         for (y = 0; y <= FIELDY; y++)
  299.             board[destination][x][y] = board[source][x][y];
  300.     startx[destination] = startx[source];
  301.     starty[destination] = starty[source];
  302.     for (which = 0; which <= 1; which++)
  303.     {    teleport[destination][which].alive = teleport[source][which].alive;
  304.         teleport[destination][which].x     = teleport[source][which].x;
  305.         teleport[destination][which].y     = teleport[source][which].y;
  306. }    }
  307.  
  308. void death(void)
  309. {    SBYTE    counter, i, pain, player, survivor, which;
  310.     ABOOL    flag, slow;
  311.  
  312.     for (player = lo; player <= hi; player++)
  313.     {    if (worm[player].lives)
  314.         {   if (!worm[player].alive)
  315.             {    slow = FALSE;
  316.                 pain = 0;
  317.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  318.                 {    if (player == worm[player].cause - FIRSTTAIL)
  319.                         pain = TAILPAIN;
  320.                     else pain = OTHERTAILPAIN;
  321.                     slow = TRUE;
  322.                 } else
  323.                 {    if (worm[player].multi > 1)
  324.                         worm[player].multi /= 2;
  325.                     if (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  326.                         pain = WORMFIREPAIN;
  327.                     else if (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  328.                         pain = HEADPAIN;
  329.                     else if (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  330.                         pain = PROTECTORPAIN;
  331.                     else if (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  332.                         pain = MISSILEPAIN;
  333.                     else switch (worm[player].cause) {
  334.                     case BOMB:
  335.                         pain = BOMBPAIN;
  336.                         break;
  337.                     case WOOD:
  338.                         pain = WOODPAIN;
  339.                         slow = TRUE;
  340.                         break;
  341.                     case FRAGMENT:
  342.                         pain = FRAGMENTPAIN;
  343.                         break;
  344.                     case KILLER:
  345.                         pain = KILLERPAIN;
  346.                         slow = TRUE;
  347.                         break;
  348.                     case SLAYER:
  349.                         pain = SLAYERPAIN;
  350.                         break;
  351.                     case STONE:
  352.                         pain = STONEPAIN;
  353.                         slow = TRUE;
  354.                         break;
  355.                     case TELEPORT:
  356.                         pain = TELEPORTPAIN;
  357.                         slow = TRUE;
  358.                         break;
  359.                     case SLIME:
  360.                         pain = SLIMEPAIN;
  361.                         slow = TRUE;
  362.                         break;
  363.                     default:
  364.                         break;
  365.                 }    }
  366.                 if (worm[player].victor >= 0 && worm[player].victor != player)
  367.                 {    wormscore(worm[player].victor, KILLWORM);
  368.                     if (worm[worm[player].victor].bias)
  369.                     {    worm[worm[player].victor].lives += pain;
  370.                         stat(worm[player].victor, LIVESLINE);
  371.                 }    }
  372.                 if (slow)
  373.                 {    worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  374.                     stat(player, SPEEDLINE); 
  375.                 }
  376.                 if (pain > worm[player].lives)
  377.                     worm[player].lives = 0;
  378.                 else worm[player].lives -= pain;
  379.                 draw(worm[player].x, worm[player].y, SKULL);
  380.                 drawcause(player, NORMAL);
  381.                 stat(player, LIVESLINE);
  382.                 if (level)
  383.                     worm[player].levelreached = level;
  384.                 else worm[player].levelreached = reallevel;
  385.                 if (worm[player].lives)
  386.                 {    flag = FALSE;
  387.                     for (i = lo; i <= hi; i++)
  388.                         if (worm[i].control == HUMAN)
  389.                             flag = TRUE;
  390.                     if (!flag || worm[player].control == HUMAN)
  391.                         effect(FXPAIN);
  392.                     // Amiga-worms only make pain sounds in demo mode
  393.                     worm[player].alive = TRUE;
  394.                     worm[player].causewait = r + CAUSEWAIT;
  395.                 } else
  396.                 {    // kill worm
  397.  
  398.                     if (worm[player].tonguereceipt)
  399.                     {    stopfx(worm[player].tonguereceipt);
  400.                         worm[player].tonguereceipt = 0L;
  401.                     }
  402.                     effect(FXWORMDEATH);
  403.                     if (ice == player)
  404.                         ice = -1;
  405.                     field[worm[player].x][worm[player].y] = SKULL;
  406.                     for (which = 0; which <= PROTECTORS; which++)
  407.                     {    if (protector[player][which].alive && protector[player][which].visible)
  408.                         {    draw(protector[player][which].x, protector[player][which].y, EMPTY);
  409.                             field[protector[player][which].x][protector[player][which].y] = EMPTY;
  410.                     }    }
  411.                     counter = 0;
  412.                     for (which = lo; which <= hi; which++)
  413.                         if (worm[which].lives)
  414.                         {    survivor = which;
  415.                             counter++;
  416.                         }
  417.                     if (counter == 1)
  418.                         wormscore(survivor, SURVIVOR);
  419.     }    }    }    }
  420.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  421.     {    // End of game
  422.         newhiscores();
  423.         effect(FXDEFEAT);
  424.         a = GAMEOVER;
  425.         if (lo == hi)
  426.             say((STRPTR) "Game over!", worm[lo].colour);
  427.         else if (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
  428.             say((STRPTR) "Green wins!", GREEN);
  429.         else if (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
  430.             say((STRPTR) "Red wins!", RED);
  431.         else if (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
  432.             say((STRPTR) "Blue wins!", BLUE);
  433.         else if (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
  434.             say((STRPTR) "Yellow wins!", YELLOW);
  435.         else say((STRPTR) "A draw!", WHITE);
  436.         waitasec();
  437.         anykey(FALSE);
  438. }    }
  439.  
  440. void drawcause(SBYTE player, SBYTE state)
  441. {    if (state == BLACK)
  442.         blitmode(BLACK);
  443.     draw(-2 + ((FIELDX + 4) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), worm[player].cause);
  444.     if (state == BLACK)
  445.         blitmode(NORMAL);
  446. }
  447.  
  448. void drawletter(SBYTE player, SBYTE letter, SBYTE state)
  449. {    if (state == BLACK)
  450.         blitmode(BLACK);
  451.     if (!worm[player].statx)
  452.         if (!worm[player].staty)
  453.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  454.                 (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  455.                 letter);
  456.         else
  457.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  458.                 (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  459.                 letter);
  460.     else
  461.         if (!worm[player].staty)
  462.             draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
  463.                 (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  464.                 letter);
  465.         else
  466.             draw(FIELDX + 4 + ((letter - FIRSTLETTER) % 4),
  467.                 (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  468.                 letter);
  469.     if (state == BLACK)
  470.         blitmode(NORMAL);
  471. }
  472.  
  473. /* NAME     enginesetup -- once-only initialization of engine variables
  474. SYNOPSIS    enginesetup(void);
  475. FUNCTION    Sets up the unchanging worm variables.
  476. MODULE      engine.c */
  477.  
  478. void enginesetup(void)
  479. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  480.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  481.     worm[0].colour    = GREEN;
  482.     worm[1].colour    = RED;
  483.     worm[2].colour    = BLUE;
  484.     worm[3].colour    = YELLOW;
  485.     worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
  486.  
  487.     systemsetup();
  488. }
  489.  
  490. /* NAME     fastloop -- things done often
  491. SYNOPSIS    fastloop(void);
  492. FUNCTION    Checks for and handles level completion.
  493. MODULE      engine.c */
  494.  
  495. void fastloop(void)
  496. {    ABOOL complete;
  497.     SBYTE advancer = -1, player, which;
  498.     
  499.     // handle level completion
  500.  
  501.     for (player = lo; player <= hi; player++)
  502.     {    complete = TRUE;
  503.         for (which = 0; which <= LETTERS; which++)
  504.             if (!letters[player][which])
  505.                 complete = FALSE;
  506.         if (complete)
  507.             advancer = player;
  508.     }
  509.     if (advancer != -1)
  510.     {    if (level++ == 0)
  511.         {    level = reallevel + 1;
  512.             reallevel = 0;
  513.         }
  514.         stopfx(0L);
  515.         if (level > levels)
  516.             effect(FXVICTORY);
  517.         else if (level >= 2)
  518.             effect(FXENDOFLEVEL);
  519.         newlevel(advancer);
  520. }    }
  521.  
  522. void fillfield(SBYTE which)
  523. {    SBYTE x, y;
  524.  
  525.     for (x = 0; x <= FIELDX; x++)
  526.         for (y = 0; y <= FIELDY; y++)
  527.         {    board[level][x][y] = which;
  528.             draw(x, y, which);
  529.         }
  530.     board[level][startx[level]][starty[level]] = EMPTY;
  531.     draw(startx[level], starty[level], START);
  532.     if (teleport[level][0].alive)
  533.     {    board[level][teleport[level][0].x][teleport[level][0].y] = TELEPORT;
  534.         draw(teleport[level][0].x, teleport[level][0].y, ONE);
  535.     }
  536.     if (teleport[level][1].alive)
  537.     {    board[level][teleport[level][1].x][teleport[level][1].y] = TELEPORT;
  538.         draw(teleport[level][1].x, teleport[level][1].y, TWO);
  539. }    }
  540.  
  541. ABOOL findempty(SBYTE* x, SBYTE* y, SBYTE first, SBYTE last)
  542. {    SBYTE count = 0, xx, yy;
  543.  
  544.     do
  545.     {    xx = rand() % (FIELDX + 1);
  546.         yy = rand() % (FIELDY + 1);
  547.     } while ((field[xx][yy] < first || field[xx][yy] > last) && ++count < PATIENCE);
  548.     if (count < PATIENCE)
  549.     {    *x = xx;
  550.         *y = yy;
  551.         return(TRUE);
  552.     } else return(FALSE);
  553. }
  554.  
  555. /* NAME     fragloop -- controls fragments
  556. SYNOPSIS    fragloop(void);
  557. FUNCTION    Controls all fragments.
  558. MODULE      engine.c */
  559.  
  560. void fragloop(void)
  561. {    SBYTE    i, j, k, thissy, which;
  562.  
  563. for (which = 0; which <= ORBS + 1; which++)
  564.     for (i = 0; i <= 7; i++)
  565.         if (frag[which][i].alive)
  566.         {   if (frag[which][i].moved)
  567.             {   draw(frag[which][i].x, frag[which][i].y, frag[which][i].last);
  568.                 field[frag[which][i].x][frag[which][i].y] = frag[which][i].last;
  569.             } else frag[which][i].moved = TRUE;
  570.             frag[which][i].x += frag[which][i].deltax;
  571.             frag[which][i].y += frag[which][i].deltay;
  572.             if (!(valid(frag[which][i].x, frag[which][i].y)))
  573.                 frag[which][i].alive = FALSE;
  574.             else
  575.             {    thissy = field[frag[which][i].x][frag[which][i].y];
  576.                 if (thissy >= FIRSTFRAGDEATH && thissy <= LASTFRAGDEATH)
  577.                 {   effect(FXTHUD);
  578.                     frag[which][i].alive = FALSE;
  579.                     if (thissy == KILLER)
  580.                     {   effect(FXKILLERDEATH);
  581.                         j = whichkiller(frag[which][i].x, frag[which][i].y);
  582.                         killer[j].alive = FALSE;
  583.                         field[killer[j].x][killer[j].y] = BONUS;
  584.                         draw(killer[j].x, killer[j].y, BONUS);
  585.                 }   }
  586.                 else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  587.                 {    effect(FXUSEPROTECTOR);
  588.                     reflect(which, i);
  589.                     frag[which][i].x += frag[which][i].deltax * 2;
  590.                     frag[which][i].y += frag[which][i].deltay * 2;
  591.                 } else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  592.                 {    frag[which][i].alive = FALSE;
  593.                     stopfx(missile[thissy - FIRSTMISSILE].receipt);
  594.                     missile[thissy - FIRSTMISSILE].alive = FALSE;
  595.                     field[missile[thissy - FIRSTMISSILE].x][missile[thissy - FIRSTMISSILE].y] = EMPTY;
  596.                     draw(missile[thissy - FIRSTMISSILE].x, missile[thissy - FIRSTMISSILE].y, EMPTY);
  597.                 } else if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  598.                 {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  599.                     {    worm[thissy - FIRSTHEAD].cause = FRAGMENT;
  600.                         worm[thissy - FIRSTHEAD].victor = -1;
  601.                         worm[thissy - FIRSTHEAD].alive = FALSE;
  602.                     } else
  603.                     {    effect(FXUSEARMOUR);
  604.                         reflect(which, i);
  605.                 }    }
  606.                 else switch(thissy) {
  607.                 case ORB:
  608.                     j = whichorb(frag[which][i].x, frag[which][i].y);
  609.                     if (orb[j].mode != ARMOUR)
  610.                         orb[j].explode = TRUE;
  611.                     else effect(FXUSEARMOUR);
  612.                     frag[which][i].alive = FALSE;
  613.                     break;
  614.                 case TELEPORT:
  615.                     j = whichteleport(frag[which][i].x, frag[which][i].y);
  616.                     if (blocked(j, frag[which][i].deltax, frag[which][i].deltay))
  617.                         frag[which][i].alive = FALSE;
  618.                     else
  619.                     {   effect(FXUSETELEPORT);
  620.                         frag[which][i].x = xwrap(teleport[level][partner(j)].x + frag[which][i].deltax);
  621.                         frag[which][i].y = ywrap(teleport[level][partner(j)].y + frag[which][i].deltay);
  622.                         frag[which][i].last = SILVER;
  623.                     }
  624.                     break;
  625.                 case BOMB:
  626.                     j = whichtimebomb(frag[which][i].x, frag[which][i].y);
  627.                     if (j != -1)
  628.                     {   frag[which][i].alive = FALSE;
  629.                         timebomb[j].alive = FALSE;
  630.                         field[timebomb[j].x][timebomb[j].y] = EMPTY;
  631.                         draw(timebomb[j].x, timebomb[j].y, EMPTY);
  632.                         bombblast(BOMB, 0, timebomb[j].x, timebomb[j].y);
  633.                     }
  634.                     break;
  635.                 case FRAGMENT:
  636.                     effect(FXTHUD);
  637.                     draw(frag[which][i].x, frag[which][i].y, EMPTY);
  638.                     frag[which][i].alive = FALSE;
  639.                     whichfrag(frag[which][i].x, frag[which][i].y, &j, &k);
  640.                     frag[j][k].alive = FALSE;
  641.                     break;
  642.                 default:
  643.                     break;
  644.                 }
  645.                 if (frag[which][i].alive)
  646.                 {   field[frag[which][i].x][frag[which][i].y] = FRAGMENT;
  647.                     draw(frag[which][i].x, frag[which][i].y, FRAGMENT);
  648.         }    }    }
  649. }
  650.  
  651. void gameloop(void)
  652. {    SBYTE player, which;
  653.  
  654.     fastloop();
  655.     gameinput();
  656.     for (player = lo; player <= hi; player++)
  657.         if (worm[player].lives && !(r % worm[player].speed) && (ice == -1 || ice == player))
  658.             wormloop(player);
  659.     if (ice == -1)
  660.     {    for (which = 0; which <= ORBS; which++)
  661.             if (orb[which].alive && !(r % orb[which].speed))
  662.                 if (orb[which].explode)
  663.                     orbexplosion(which);
  664.                 else orbloop(which);
  665.         if (!(r % killerspeed))
  666.             killerloop();
  667.         if (!(r % fragspeed))
  668.             fragloop();
  669.         if (!(r % MISSILESPEED))
  670.             missileloop();
  671.     }
  672.     if (a == PLAYGAME)
  673.     {    death();
  674.         if (!(r % VERYSLOW))
  675.             slowloop();
  676. }    }
  677.  
  678. void killall(void)
  679. {    SBYTE iwhich, which;
  680.  
  681.     for (which = 0; which <= ORBS; which++)
  682.         orb[which].alive = FALSE;
  683.     for (which = 0; which <= KILLERS; which++)
  684.         killer[which].alive = FALSE;
  685.     for (which = 0; which <= ORBS + 1; which++)
  686.         for (iwhich = 0; iwhich <= 7; iwhich++)
  687.             frag[which][iwhich].alive = FALSE;
  688.     for (which = 0; which <= 3; which++)
  689.         if (missile[which].alive)
  690.         {   stopfx(missile[which].receipt);
  691.             missile[which].alive = FALSE;
  692.         }
  693.     for (which = 0; which <= TIMEBOMBS; which++)
  694.         timebomb[which].alive = FALSE;
  695.     teleport[level][2].alive = FALSE;
  696.     teleport[level][3].alive = FALSE;
  697. }
  698.  
  699. void killerloop(void)
  700. {    ABOOL    happy;
  701.     UBYTE    count;
  702.     SBYTE    which, x, xx, y, yy;
  703.  
  704.     for (which = 0; which <= KILLERS; which++)
  705.         if (killer[which].alive)
  706.         {    happy = FALSE;
  707.             for (x = killer[which].x - 1; x <= killer[which].x + 1; x++)
  708.                 for (y = killer[which].y - 1; y <= killer[which].y + 1; y++)
  709.                     if (field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  710.                         happy = TRUE;
  711.             if ((!happy) || (!(rand() % RESTFULNESS)))
  712.             {    x = (rand() % 3) - 1;
  713.                 y = (rand() % 3) - 1;
  714.                 if (valid(killer[which].x + x, killer[which].y + y) && (x || y)
  715.                 && field[killer[which].x + x][killer[which].y + y] >= FIRSTKILLER && field[killer[which].x + x][killer[which].y + y] <= LASTKILLER && field[killer[which].x + x][killer[which].y + y] != KILLER)
  716.                 {    field[killer[which].x][killer[which].y] = killer[which].last;
  717.                     draw(killer[which].x, killer[which].y, killer[which].last);
  718.                     killer[which].x += x;
  719.                     killer[which].y += y;
  720.                     killer[which].last = field[killer[which].x][killer[which].y];
  721.                     field[killer[which].x][killer[which].y] = KILLER;
  722.                     draw(killer[which].x, killer[which].y, KILLER);
  723.             }    }
  724.             if (!frag[ORBS + 1][which].alive && !(rand() % KILLERFIREFREQ))
  725.             {    count = 0;
  726.                 do
  727.                 {    x = (rand() % 3) - 1;
  728.                     y = (rand() % 3) - 1;
  729.                     xx = killer[which].x + x;
  730.                     yy = killer[which].y + y;
  731.                 } while (((!x && !y) || xx < 0 || xx > FIELDX || yy < 0 || yy > FIELDY || field[xx][yy] > LASTKILLERFIRE) && ++count < PATIENCE);
  732.                 if (count < PATIENCE)
  733.                 {    effect(FXKILLERFIRE);
  734.                     frag[ORBS + 1][which].alive = TRUE;
  735.                     frag[ORBS + 1][which].x = killer[which].x;
  736.                     frag[ORBS + 1][which].y = killer[which].y;
  737.                     frag[ORBS + 1][which].deltax = x;
  738.                     frag[ORBS + 1][which].deltay = y;
  739.                     frag[ORBS + 1][which].moved = FALSE;
  740.                     frag[ORBS + 1][which].last = EMPTY;
  741. }        }    }    }
  742.  
  743. void levelappend(void)
  744. {    UBYTE oldlevel;
  745.  
  746.     if (levels < MAXLEVELS)
  747.     {    oldlevel = level;
  748.         level = ++levels;
  749.         newfield();
  750.         level = oldlevel;
  751.         saylevel(WHITE);
  752. }    }
  753.  
  754. void leveldelete(void)
  755. {    SBYTE i;
  756.  
  757.     // pull boards
  758.  
  759.     if (levels > 1)
  760.     {    if (level < levels)
  761.             for (i = level; i < levels; i++)
  762.                 copyfield(i + 1, i);
  763.         else
  764.             level--;
  765.         levels--;
  766.         saylevel(WHITE);
  767.         renderboard();
  768. }    }
  769.  
  770. void levelerase(void)
  771. {    newfield();
  772.     renderboard();
  773. }
  774.  
  775. void levelinsert(void)
  776. {    SBYTE i;
  777.  
  778.     // push boards
  779.  
  780.     if (levels < MAXLEVELS)
  781.     {    for (i = levels; i >= level; i--)
  782.             copyfield(i, i + 1);
  783.         levels++;
  784.         saylevel(WHITE);
  785.         newfield();
  786.         renderboard();
  787. }    }
  788.  
  789. ABOOL loadfields(STRPTR fieldname)
  790. {    SBYTE                i, j;
  791.     TEXT                IOBuffer[NAMELENGTH + 1];
  792.  
  793.     // open file
  794.  
  795.     if (!ZOpen(fieldname, FALSE))
  796.         return FALSE;
  797.  
  798.     // read header
  799.  
  800.     if (!ZRead(IOBuffer, 10))
  801.     {    ZClose();
  802.         return FALSE;
  803.     }
  804.     if (strcmp(IOBuffer, "FSET 4.1"))
  805.     {    ZClose();
  806.         return FALSE;
  807.     }
  808.     levels                            = IOBuffer[9];
  809.  
  810.     // read high score table
  811.  
  812.     for (i = 0; i <= HISCORES; i++)
  813.     {    if (!ZRead(IOBuffer, 6))
  814.         {    ZClose();
  815.             return FALSE;
  816.         }
  817.         hiscore[i].fresh            =  FALSE;
  818.         hiscore[i].player            =  IOBuffer[0];
  819.         hiscore[i].level            =  IOBuffer[1];
  820.         hiscore[i].score            = (IOBuffer[3] * 65536)
  821.                                     + (IOBuffer[4] * 256)
  822.                                     +  IOBuffer[5];
  823.  
  824.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  825.         {    ZClose();
  826.             return FALSE;
  827.         }
  828.         for (j = 0; j <= NAMELENGTH; j++)
  829.             hiscore[i].name[j]        = IOBuffer[j];
  830.     }
  831.  
  832.     // read level data
  833.  
  834.     for (i = 0; i <= levels; i++)
  835.     {   if (!ZRead(IOBuffer, 8))
  836.         {    ZClose();
  837.             return FALSE;
  838.         }
  839.         startx[i]                    =  IOBuffer[0];
  840.         starty[i]                    =  IOBuffer[1];
  841.         teleport[i][0].alive        =  IOBuffer[2];
  842.         teleport[i][0].x            =  IOBuffer[3];
  843.         teleport[i][0].y            =  IOBuffer[4];
  844.         teleport[i][1].alive        =  IOBuffer[5];
  845.         teleport[i][1].x            =  IOBuffer[6];
  846.         teleport[i][1].y            =  IOBuffer[7];
  847.  
  848.         if (!ZRead((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
  849.         {    ZClose();
  850.             return FALSE;
  851.     }    }
  852.  
  853.     // no need to read version string
  854.  
  855.     ZClose();
  856.     modified = FALSE;
  857.     return TRUE;
  858. }
  859.  
  860. void matchteleports(void)
  861. {    SBYTE which;
  862.  
  863.     for (which = 0; which <= levels; which++)
  864.         if (teleport[which][0].alive == TRUE && teleport[which][1].alive == FALSE)
  865.         {    board[which][teleport[which][0].x][teleport[which][0].y] = EMPTY;
  866.             teleport[which][0].alive = FALSE;
  867.             if (level == which && a == FIELDEDIT)
  868.                 draw(teleport[which][0].x, teleport[which][0].y, EMPTY);
  869.         } else if (teleport[which][0].alive == FALSE && teleport[which][1].alive == TRUE)
  870.         {    board[which][teleport[which][1].x][teleport[which][1].y] = EMPTY;
  871.             teleport[which][1].alive = FALSE;
  872.             if (level == which && a == FIELDEDIT)
  873.                 draw(teleport[which][1].x, teleport[which][1].y, EMPTY);
  874. }        }
  875.  
  876. /* NAME     missileloop -- controls missiles
  877. SYNOPSIS    missileloop(void);
  878. FUNCTION    Controls all killers.
  879. MODULE      engine.c */
  880.  
  881. void missileloop(void)
  882. {    SBYTE    distx, disty, distance, iwhich, player, thissy, which;
  883.     UBYTE   bestdistance;
  884.     
  885.     for (player = lo; player <= hi; player++)
  886.     {   if (missile[player].alive && (ice == -1 || ice == player))
  887.         {   bestdistance = (UBYTE) -1;
  888.             for (which = lo; which <= hi; which++)
  889.                 if (which != player && worm[which].lives > 0 && !worm[which].bias)
  890.                 {   distx = abs(worm[which].x - missile[player].x);
  891.                     disty = abs(worm[which].y - missile[player].y);
  892.                     if (distx < disty)
  893.                         distance = distx;
  894.                     else distance = disty;
  895.                     if (distance <= bestdistance)
  896.                     {   bestdistance = distance;
  897.                         missile[player].deltax = bsign(worm[which].x - missile[player].x);
  898.                         missile[player].deltay = bsign(worm[which].y - missile[player].y);
  899.                 }    }
  900.             for (which = lo; which <= hi; which++)
  901.                 if (which != player && missile[which].alive)
  902.                 {   distx = abs(missile[which].x - missile[player].x);
  903.                     disty = abs(missile[which].y - missile[player].y);
  904.                     if (distx < disty)
  905.                         distance = distx;
  906.                     else distance = disty;
  907.                     if (distance <= bestdistance)
  908.                     {   bestdistance = distance;
  909.                         missile[player].deltax = bsign(missile[which].x - missile[player].x);
  910.                         missile[player].deltay = bsign(missile[which].y - missile[player].y);
  911.                 }    }
  912.             for (which = 0; which <= ORBS; which++)
  913.                 if (orb[which].alive)
  914.                 {   distx = abs(orb[which].x - missile[player].x) * 2;
  915.                     disty = abs(orb[which].y - missile[player].y) * 2;
  916.                     if (distx < disty)
  917.                         distance = distx;
  918.                     else distance = disty;
  919.                     if (distance <= bestdistance)
  920.                     {   bestdistance = distance;
  921.                         missile[player].deltax = bsign(orb[which].x - missile[player].x);
  922.                         missile[player].deltay = bsign(orb[which].y - missile[player].y);
  923.                 }    }
  924.             for (which = 0; which <= KILLERS; which++)
  925.                 if (killer[which].alive)
  926.                 {    distx = abs(killer[which].x - missile[player].x) * 2;
  927.                     disty = abs(killer[which].y - missile[player].y) * 2;
  928.                     if (distx < disty)
  929.                         distance = distx;
  930.                     else distance = disty;
  931.                     if (distance <= bestdistance)
  932.                     {   bestdistance = distance;
  933.                         missile[player].deltax = bsign(killer[which].x - missile[player].x);
  934.                         missile[player].deltay = bsign(killer[which].y - missile[player].y);
  935.                 }    }
  936.             if (missile[player].moved)
  937.             {   draw(missile[player].x, missile[player].y, EMPTY);
  938.                 field[missile[player].x][missile[player].y] = EMPTY;
  939.             } else missile[player].moved = TRUE;
  940.             if (bestdistance == (UBYTE) -1)
  941.             {   stopfx(missile[player].receipt);
  942.                 missile[player].alive = FALSE;
  943.             } else
  944.             {   missile[player].x += missile[player].deltax;
  945.                 missile[player].y += missile[player].deltay;
  946.                 thissy = field[missile[player].x][missile[player].y];
  947.                 if (thissy >= FIRSTLETTER && thissy <= WOOD)
  948.                 {   stopfx(missile[player].receipt);
  949.                     missile[player].alive = FALSE;
  950.                     if (thissy == KILLER)
  951.                     {   effect(FXKILLERDEATH);
  952.                         which = whichkiller(missile[player].x, missile[player].y);
  953.                         killer[which].alive = FALSE;
  954.                         field[killer[which].x][killer[which].y] = BONUS;
  955.                         draw(killer[which].x, killer[which].y, BONUS);
  956.                         wormscore(player, KILLKILLER);
  957.                         if (worm[player].bias)
  958.                         {   worm[player].lives += KILLERBLOOD;
  959.                             stat(player, LIVESLINE);
  960.                 }   }   }
  961.                 else if (thissy == FRAGMENT)
  962.                 {   stopfx(missile[player].receipt);
  963.                     missile[player].alive = FALSE;
  964.                     whichfrag(missile[player].x, missile[player].y, &which, &iwhich);
  965.                     frag[which][iwhich].alive = FALSE;
  966.                 } else if (thissy == ORB)
  967.                 {   stopfx(missile[player].receipt);
  968.                     missile[player].alive = FALSE;
  969.                     which = whichorb(missile[player].x, missile[player].y);
  970.                     if (orb[which].mode != ARMOUR)
  971.                     {   effect(FXORBDEATH);
  972.                         orb[which].alive = FALSE;
  973.                         draw(orb[which].x, orb[which].y, BONUS);
  974.                         field[orb[which].x][orb[which].y] = BONUS;
  975.                         wormscore(player, orb[which].score);
  976.                         if (worm[player].bias)
  977.                         {   worm[player].lives += ORBBLOOD;
  978.                             stat(player, LIVESLINE);
  979.                         }
  980.                     } else effect(FXUSEARMOUR);
  981.                 } else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  982.                 {   if (player != thissy - FIRSTPROTECTOR)
  983.                     {   stopfx(missile[player].receipt);
  984.                         effect(FXUSEPROTECTOR);
  985.                         missile[player].alive = FALSE;
  986.                 }   }
  987.                 else if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  988.                 {   stopfx(missile[player].receipt);
  989.                     missile[player].alive = FALSE;
  990.                     if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  991.                     {    worm[thissy - FIRSTHEAD].cause = FIRSTMISSILE + player;
  992.                         worm[thissy - FIRSTHEAD].victor = player;
  993.                         worm[thissy - FIRSTHEAD].alive = FALSE;
  994.                     } else effect(FXUSEARMOUR);
  995.                 } else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  996.                 {   stopfx(missile[player].receipt);
  997.                     stopfx(missile[thissy - FIRSTMISSILE].receipt);
  998.                     missile[player].alive = FALSE;
  999.                     missile[thissy - FIRSTMISSILE].alive = FALSE;
  1000.                     field[missile[which].x][missile[which].y] = BONUS;
  1001.                     draw(missile[which].x, missile[which].y, BONUS);
  1002.                 } else if (thissy == TELEPORT)
  1003.                 {   which = whichteleport(missile[player].x, missile[player].y);
  1004.                     if (blocked(which, missile[player].deltax, missile[player].deltay))
  1005.                     {   stopfx(missile[player].receipt);
  1006.                         missile[player].alive = FALSE;
  1007.                     } else
  1008.                     {   effect(FXUSETELEPORT);
  1009.                         missile[player].x = xwrap(teleport[level][partner(which)].x + missile[player].deltax);
  1010.                         missile[player].y = ywrap(teleport[level][partner(which)].y + missile[player].deltay);
  1011.                 }   }
  1012.                 else if (thissy == BOMB)
  1013.                 {   which = whichtimebomb(missile[player].x, missile[player].y);
  1014.                     if (which != -1)
  1015.                     {   stopfx(missile[player].receipt);
  1016.                         missile[player].alive = FALSE;
  1017.                         timebomb[which].alive = FALSE;
  1018.                         field[timebomb[which].x][timebomb[which].y] = EMPTY;
  1019.                         draw(timebomb[which].x, timebomb[which].y, EMPTY);
  1020.                         bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
  1021.                 }   }
  1022.                 else if (thissy == SKULL)
  1023.                 {    stopfx(missile[player].receipt);
  1024.                     missile[player].alive = FALSE;
  1025.                 }
  1026.                 if (missile[player].alive)
  1027.                 {    draw(missile[player].x, missile[player].y, FIRSTMISSILE + player);
  1028.                     field[missile[player].x][missile[player].y] = FIRSTMISSILE + player;
  1029. }   }   }   }   }
  1030.  
  1031. void newfield(void)
  1032. {    int x, y;
  1033.  
  1034.     teleport[level][0].alive = FALSE;
  1035.     teleport[level][1].alive = FALSE;
  1036.     startx[level] = FIELDX / 2;
  1037.     starty[level] = FIELDY / 2;
  1038.  
  1039.     if (level)
  1040.         for (x = 0; x <= FIELDX; x++)
  1041.             for (y = 0; y <= FIELDY; y++)
  1042.                 board[level][x][y] = EMPTY;
  1043.     else for (x = 0; x <= FIELDX; x++)
  1044.         for (y = 0; y <= FIELDY; y++)
  1045.             board[0][x][y] = SILVER;
  1046. }
  1047.  
  1048. void newfields(void)
  1049. {    if (verify())
  1050.     {   pathname = (STRPTR) DEFAULTSET;
  1051.         levels = DEFAULTLEVELS;
  1052.         modified = FALSE;
  1053.         for (level = 0; level <= levels; level++)
  1054.             newfield();
  1055.         clearhiscores();
  1056.         level = 1;
  1057.         if (a == FIELDEDIT)
  1058.         {    renderboard();
  1059.             saylevel(WHITE);
  1060.         } else
  1061.             hiscores();
  1062. }    }
  1063.  
  1064. void newgame(void)
  1065. {    SBYTE player;
  1066.  
  1067.     if (worm[0].control != NONE)
  1068.         lo = 0;
  1069.     else if (worm[1].control != NONE)
  1070.         lo = 1;
  1071.     else if (worm[2].control != NONE)
  1072.         lo = 2;
  1073.     else lo = 3;
  1074.     if (worm[3].control != NONE)
  1075.         hi = 3;
  1076.     else if (worm[2].control != NONE)
  1077.         hi = 2;
  1078.     else if (worm[1].control != NONE)
  1079.         hi = 1;
  1080.     else hi = 0;
  1081.  
  1082.     for (player = 0; player <= 3; player++)
  1083.         worm[player].lives = 0;
  1084.  
  1085.     r            = -1;
  1086.     trainer        = FALSE;
  1087.     ice            = -1;
  1088.     reallevel    = 0;
  1089.     level        = 1;
  1090.     a            = PLAYGAME;
  1091.     clearstats();
  1092.     newlevel(rand() % 4);
  1093. }
  1094.  
  1095. void newhiscores(void)
  1096. {
  1097. PERSIST    TEXT    amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R.J. Mical", "Dave Morse"};
  1098.         SBYTE    iwhich, player, which;
  1099.  
  1100. for (player = lo; player <= hi; player++)
  1101.     for (which = 0; which <= HISCORES; which++)
  1102.         if (worm[player].control != NONE && worm[player].score >= hiscore[which].score)
  1103.         {    // push all worse hiscores down
  1104.  
  1105.             if (which < HISCORES)
  1106.                 for (iwhich = HISCORES; iwhich >= which + 1; iwhich--)
  1107.                 {    hiscore[iwhich].player    = hiscore[iwhich - 1].player;
  1108.                     hiscore[iwhich].score    = hiscore[iwhich - 1].score;
  1109.                     hiscore[iwhich].level    = hiscore[iwhich - 1].level;
  1110.                     hiscore[iwhich].fresh    = hiscore[iwhich - 1].fresh;
  1111.                     strcpy(hiscore[iwhich].name, hiscore[iwhich - 1].name);
  1112.                 }
  1113.  
  1114.             modified = TRUE;
  1115.             hiscore[which].player = player;
  1116.             hiscore[which].score = worm[player].score;
  1117.             hiscore[which].level = worm[player].levelreached;
  1118.             if (worm[player].control == AMIGA)
  1119.             {    strcpy(hiscore[which].name, amiganame[player]);
  1120.                 hiscore[which].fresh = FALSE;
  1121.             } else
  1122.             {    strcpy(hiscore[which].name, "(New)");
  1123.                 hiscore[which].fresh = TRUE;
  1124.             }
  1125.             break;
  1126. }        }
  1127.  
  1128. void newlevel(SBYTE player)
  1129. {    SBYTE    iwhich, which;
  1130.  
  1131.     if (!level)
  1132.     {   delay            = GAMEDELAY;
  1133.         fragspeed        = FRAGSPEED;
  1134.         killerspeed        = KILLERSPEED;
  1135.         orbspeed        = ORBSPEED;
  1136.         killerfreq        = KILLERFREQSTART;
  1137.         orbfreq            = ORBFREQSTART;
  1138.         slimefreq        = SLIMEFREQSTART;
  1139.         slimegrowfreq    = SLIMEGROWFREQSTART;
  1140.     } else if (level >= 2 && worm[player].lives)
  1141.         rundown(player);
  1142.     if (a == PLAYGAME)
  1143.     {    if (level > levels)
  1144.         {    for (which = lo; which <= hi; which++)
  1145.                 if (worm[which].lives)
  1146.                   {    wormscore(which, CHAMPION);
  1147.                     worm[which].levelreached = -1;
  1148.                 }
  1149.             celebrate();
  1150.             newhiscores();
  1151.             titlescreen();
  1152.         } else
  1153.         {    killall();
  1154.             clearletters();
  1155.             if (worm[player].lives)
  1156.                 saylevel(worm[player].colour);
  1157.             else saylevel(WHITE);
  1158.             orientworms();
  1159.             changefield();
  1160.             renderboard();
  1161.             if (level)
  1162.             {    if (level <= FASTESTLEVEL)
  1163.                     delay = GAMEDELAY - (level * GAMEDELAYPERLEVEL);
  1164.                 putletter(-1);
  1165.                 fragspeed = FRAGSPEED - (level / FRAGINCLEVELS);
  1166.                 if (fragspeed < VERYFAST)
  1167.                     fragspeed = VERYFAST;
  1168.                 orbspeed = ORBSPEED - (level / ORBINCLEVELS);
  1169.                 if (orbspeed < VERYFAST)
  1170.                     orbspeed = VERYFAST;
  1171.                 killerspeed = KILLERSPEED - (level / KILLERINCLEVELS);
  1172.                 if (killerspeed < VERYFAST)
  1173.                     killerspeed = VERYFAST;
  1174.                 killerfreq = KILLERFREQSTART - (KILLERFREQMOD * level);
  1175.                 if (killerfreq < KILLERFREQEND)
  1176.                     killerfreq = KILLERFREQEND;
  1177.                 orbfreq = ORBFREQSTART - (ORBFREQMOD * level);
  1178.                 if (orbfreq < ORBFREQEND)
  1179.                     orbfreq = ORBFREQEND;
  1180.                 slimefreq = SLIMEFREQSTART - (SLIMEFREQMOD * level);
  1181.                 if (slimefreq < SLIMEFREQEND)
  1182.                     slimefreq = SLIMEFREQEND;
  1183.                 slimegrowfreq = SLIMEGROWFREQSTART - (SLIMEGROWFREQMOD * level);
  1184.                 if (slimegrowfreq < SLIMEGROWFREQEND)
  1185.                     slimegrowfreq = SLIMEGROWFREQEND;
  1186.                 secondsperlevel = SECONDSPERLEVEL;
  1187.                 for (which = 0; which <= 3; which++)
  1188.                 {   if (!worm[which].lives && worm[which].control != NONE)
  1189.                     {   // create (or resurrect) a worm
  1190.  
  1191.                         worm[which].lives      = STARTLIVES;
  1192.                         worm[which].score      = 0;
  1193.                         worm[which].alive      = TRUE;
  1194.                         worm[which].oldscore   = 0;
  1195.                         worm[which].armour     = 0;
  1196.                         worm[which].tongue     = 0;
  1197.                         worm[which].nitro      = FALSE;
  1198.                         worm[which].mode       = NULL;
  1199.                         worm[which].power      = 0;
  1200.                         worm[which].bias       = 0;
  1201.                         worm[which].multi      = 1;
  1202.                         worm[which].ice        = 0;
  1203.                         worm[which].victor     = -1;
  1204.                         worm[which].ammo       = 0;
  1205.                         worm[which].affixer    = FALSE;
  1206.                         worm[which].causewait  = (ULONG) -1;
  1207.                         worm[which].last       = FIRSTTAIL + which;
  1208.                         worm[which].pos        = -1;
  1209.                         for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)                    protector[which][iwhich].alive = FALSE;
  1210.                             for (iwhich = 0; iwhich <= LINES; iwhich++)
  1211.                                 stat(which, iwhich);
  1212.     }    }    }    }    }
  1213.     clearjoystick();
  1214.     clearkybd();
  1215.     ignorenextjoy = FALSE;
  1216.     outoftime = 0;
  1217.     resettime();
  1218. }
  1219.  
  1220. void orbexplosion(SBYTE which)
  1221. {    SBYTE iwhich;
  1222.  
  1223.     effect(FXEXPLODE);
  1224.     orb[which].alive = FALSE;
  1225.     for (iwhich = 0; iwhich <= 7; iwhich++)
  1226.     {    frag[which][iwhich].alive = TRUE;
  1227.         frag[which][iwhich].x = orb[which].x;
  1228.         frag[which][iwhich].y = orb[which].y;
  1229.         frag[which][iwhich].moved = TRUE;
  1230.         frag[which][iwhich].last = EMPTY;
  1231.         switch (iwhich)
  1232.         {
  1233.         case 0:
  1234.             frag[which][iwhich].deltax = 0;
  1235.             frag[which][iwhich].deltay = -1;
  1236.             break;
  1237.         case 1:
  1238.             frag[which][iwhich].deltax = 1;
  1239.             frag[which][iwhich].deltay = -1;
  1240.             break;
  1241.         case 2:
  1242.             frag[which][iwhich].deltax = 1;
  1243.             frag[which][iwhich].deltay = 0;
  1244.             break;
  1245.         case 3:
  1246.             frag[which][iwhich].deltax = 1;
  1247.             frag[which][iwhich].deltay = 1;
  1248.             break;
  1249.         case 4:
  1250.             frag[which][iwhich].deltax = 0;
  1251.             frag[which][iwhich].deltay = 1;
  1252.             break;
  1253.         case 5:
  1254.             frag[which][iwhich].deltax = -1;
  1255.             frag[which][iwhich].deltay = 1;
  1256.             break;
  1257.         case 6:
  1258.             frag[which][iwhich].deltax = -1;
  1259.             frag[which][iwhich].deltay = 0;
  1260.             break;
  1261.         case 7:
  1262.             frag[which][iwhich].deltax = -1;
  1263.             frag[which][iwhich].deltay = -1;
  1264.             break;
  1265.         default:
  1266.             break;
  1267. }    }    }
  1268.  
  1269. /* NAME     orbloop -- controls orbs
  1270. SYNOPSIS    orbloop(SBYTE);
  1271. FUNCTION    Controls an orb.
  1272. MODULE      engine.c */
  1273.  
  1274. void orbloop(SBYTE which) {
  1275. SBYTE    frontx, fronty, iiwhich, iwhich, player, newdeltax, newdeltay,
  1276.         rearx, reary, thissy, x, xx, y, yy;
  1277. ULONG    score = 0L;
  1278.  
  1279. // erase previous image
  1280.     
  1281. if (orb[which].moved)
  1282.     if (field[orb[which].x][orb[which].y] != ORB)
  1283.         orb[which].moved = FALSE;
  1284.     else
  1285.     {    draw(orb[which].x, orb[which].y, orb[which].last);
  1286.         field[orb[which].x][orb[which].y] = orb[which].last;
  1287.     }
  1288. else orb[which].moved = TRUE;
  1289.  
  1290. // bounce/move
  1291.  
  1292. frontx    = xwrap(orb[which].x + orb[which].deltax);    // look in front
  1293. fronty    = ywrap(orb[which].y + orb[which].deltay);
  1294. rearx    = xwrap(orb[which].x - orb[which].deltax);    // look behind
  1295. reary    = ywrap(orb[which].y - orb[which].deltay);
  1296. if (bounceorb(which, frontx, fronty))
  1297. {    bouncekiller(which, frontx, fronty);
  1298.     newdeltax = -orb[which].deltax;    // default bounce angle is 180°
  1299.     newdeltay = -orb[which].deltay;
  1300.     if (!bounceorb(which, frontx, reary))
  1301.     {    if (bounceorb(which, rearx, fronty))
  1302.         {    bouncekiller(which, rearx, fronty);
  1303.             newdeltax = orb[which].deltax;
  1304.     }    }
  1305.     else if (!bounceorb(which, rearx, fronty))
  1306.     {    bouncekiller(which, rearx, fronty);
  1307.         newdeltay = orb[which].deltay;
  1308.     }
  1309.     orb[which].deltax = newdeltax;
  1310.     orb[which].deltay = newdeltay;
  1311. }
  1312. orb[which].x = xwrap(orb[which].x + orb[which].deltax);
  1313. orb[which].y = ywrap(orb[which].y + orb[which].deltay);
  1314. orb[which].last = EMPTY;
  1315.  
  1316. // collision detection
  1317.  
  1318. if (orb[which].alive)
  1319. {    x = orb[which].x;
  1320.     y = orb[which].y;
  1321.     thissy = field[x][y];
  1322.     if (thissy <= LASTOBJECT)
  1323.     {    score = object[thissy].score;
  1324.         if (thissy != SLAYER && thissy != BOMB)
  1325.             effect(FXGETOBJECT);
  1326.         if (thissy == AMMO || thissy == SLAYER)
  1327.         {    if (orb[which].mode != ARMOUR)
  1328.                 orb[which].explode = TRUE;
  1329.             else effect(FXUSEARMOUR);
  1330.         } else if (thissy == NITRO || thissy == POWER)
  1331.         {    effect(FXGETNITRO);
  1332.             orb[which].speed = speedup(orb[which].speed, TRUE);
  1333.         } else if (thissy == LIFE || thissy == ICE || thissy == TREASURE)
  1334.             orbsplit(which);
  1335.         else switch(thissy) {
  1336.         case ARMOUR:
  1337.             orb[which].armour += MODEADD + (rand() % MODERAND);
  1338.             orb[which].mode = ARMOUR;
  1339.             break;
  1340.         case TONGUE:
  1341.             orb[which].tongue += MODEADD + (rand() % MODERAND);
  1342.             orb[which].mode = TONGUE;
  1343.             break;
  1344.         case BOMB:
  1345.             iwhich = whichtimebomb(x, y);
  1346.             timebomb[iwhich].alive = FALSE;
  1347.             draw(x, y, ORB); /* so the user understands what is happening
  1348.             *before* the s-l-o-w bombblast() occurs */
  1349.             bombblast(ORB, which, x, y);
  1350.             break;
  1351.         case PROTECTOR:
  1352.             for (player = lo; player <= hi; player++)
  1353.                 if (worm[player].lives)
  1354.                     for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
  1355.                         if (protector[player][iwhich].alive)
  1356.                         {    protector[player][iwhich].alive = FALSE;    
  1357.                             if (protector[player][iwhich].visible)
  1358.                             {    draw(protector[player][iwhich].x, protector[player][iwhich].y, EMPTY);
  1359.                                 field[protector[player][iwhich].x][protector[player][iwhich].y] = EMPTY;
  1360.                         }    }
  1361.             break;
  1362.         case MISSILE:
  1363.             for (player = lo; player <= hi; player++)
  1364.                 if (missile[player].alive)
  1365.                 {    missile[player].alive = FALSE;
  1366.                     draw(missile[player].x, missile[player].y, EMPTY);
  1367.                     field[missile[player].x][missile[player].y] = EMPTY;
  1368.                 }
  1369.             break;
  1370.         case MULTIPLIER:
  1371.             orb[which].multi *= 2;
  1372.             if (orb[which].multi > MULTILIMIT)
  1373.                 orb[which].multi = MULTILIMIT;
  1374.             break;
  1375.         case BIAS:
  1376.             for (player = lo; player <= hi; player++)
  1377.                    if (worm[player].lives && worm[player].bias)
  1378.                 {    worm[player].bias = 0;
  1379.                     stat(player, BIASLINE);
  1380.                 }
  1381.             break;
  1382.         case AFFIXER:
  1383.             for (player = lo; player <= hi; player++)
  1384.                 if (worm[player].lives)
  1385.                     worm[player].affixer = FALSE;
  1386.             break;
  1387.         case SWITCHER:
  1388.             for (x = 0; x <= FIELDX; x++)
  1389.                 for (y = 0; y <= FIELDY; y++)
  1390.                     if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  1391.                     {   field[x][y] = WOOD;
  1392.                         draw(x, y, WOOD);
  1393.                     }
  1394.             break;
  1395.         case GROWER:
  1396.             effect(FXGETGROWER);
  1397.             for (x = 0; x <= FIELDX; x++)
  1398.                 for (y = 0; y <= FIELDY; y++)
  1399.                     if (field[x][y] == WOOD)
  1400.                         for (xx = x - 1; xx <= x + 1; xx++)
  1401.                             for (yy = y - 1; yy <= y + 1; yy++)
  1402.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY)
  1403.                                     field[xx][yy] = TEMPWOOD;
  1404.             for (x = 0; x <= FIELDX; x++)
  1405.                 for (y = 0; y <= FIELDY; y++)
  1406.                     if (field[x][y] == TEMPWOOD)
  1407.                     {    field[x][y] = WOOD;
  1408.                         draw(x, y, WOOD);
  1409.                     }
  1410.             break;
  1411.         default:
  1412.             break;
  1413.     }   }
  1414.     else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  1415.     {   effect(FXUSEPROTECTOR);
  1416.         effect(FXORBDEATH);
  1417.         orb[which].alive = FALSE;
  1418.         wormscore(thissy - FIRSTPROTECTOR, orb[which].score);
  1419.         if (worm[thissy - FIRSTPROTECTOR].bias)
  1420.         {   worm[thissy - FIRSTPROTECTOR].lives += ORBBLOOD;
  1421.             stat(thissy - FIRSTPROTECTOR, LIVESLINE);
  1422.     }   }
  1423.     else if (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  1424.     {   if (orb[which].mode == TONGUE)
  1425.         {   effect(FXUSETONGUE);
  1426.             if (worm[thissy - FIRSTTAIL].lives && worm[thissy - FIRSTTAIL].bias)
  1427.             {   orb[which].last = GOLD;
  1428.                 score = TURNTOGOLD;
  1429.             } else
  1430.             {   orb[which].last = SILVER;
  1431.                 score = TURNTOSILVER;
  1432.         }   }
  1433.         else
  1434.         {   if (worm[thissy - FIRSTTAIL].alive)
  1435.             {   effect(FXORBDEATH);
  1436.                 wormscore(thissy - FIRSTTAIL, orb[which].score);
  1437.                 if (worm[thissy - FIRSTTAIL].bias)
  1438.                 {   worm[thissy - FIRSTTAIL].lives += ORBBLOOD;
  1439.                     stat(thissy - FIRSTTAIL, LIVESLINE);
  1440.             }   }
  1441.             orb[which].alive = FALSE;
  1442.             field[x][y] = BONUS;
  1443.             draw(x, y, BONUS);
  1444.     }   }
  1445.     else if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  1446.     {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  1447.         {    worm[thissy - FIRSTHEAD].cause = ORB;
  1448.             worm[thissy - FIRSTHEAD].victor = -1;
  1449.             worm[thissy - FIRSTHEAD].alive = FALSE;
  1450.             if (orb[which].mode == ARMOUR)
  1451.             {    effect(FXUSEARMOUR);
  1452.                 score = KILLWORM;
  1453.             } else
  1454.             {   effect(FXORBDEATH);
  1455.                 orb[which].alive = FALSE;
  1456.                 wormscore(thissy - FIRSTHEAD, orb[which].score);
  1457.                 if (worm[thissy - FIRSTHEAD].bias)
  1458.                 {   worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
  1459.                     stat(thissy - FIRSTHEAD, LIVESLINE);
  1460.         }   }   }
  1461.         else
  1462.         {    effect(FXUSEARMOUR);
  1463.             effect(FXORBDEATH);
  1464.             orb[which].alive = FALSE;
  1465.             wormscore(thissy - FIRSTHEAD, orb[which].score);
  1466.             if (worm[thissy - FIRSTHEAD].bias)
  1467.             {   worm[thissy - FIRSTHEAD].lives += ORBBLOOD;
  1468.                 stat(thissy - FIRSTHEAD, LIVESLINE);
  1469.         }   }
  1470.         orb[which].last = thissy - FIRSTHEAD + FIRSTTAIL; // note sign issues
  1471.     } else if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  1472.     {    score = ORBLETTER;
  1473.         putletter(-1);
  1474.     } else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  1475.     {    missile[thissy - FIRSTMISSILE].alive = FALSE;
  1476.         if (orb[which].mode != ARMOUR)
  1477.         {   effect(FXORBDEATH);
  1478.             wormscore(thissy - FIRSTMISSILE, orb[which].score);
  1479.             if (worm[thissy - FIRSTMISSILE].bias)
  1480.             {   worm[thissy - FIRSTMISSILE].lives += ORBBLOOD;
  1481.                 stat(thissy - FIRSTMISSILE, LIVESLINE);
  1482.             }
  1483.             orb[which].alive = FALSE;
  1484.             draw(x, y, BONUS);
  1485.             field[x][y] = BONUS;
  1486.         } else effect(FXUSEARMOUR);
  1487.     } else switch (thissy) {
  1488.     case EMPTY:
  1489.         score = EMPTYPOINT;
  1490.         break;
  1491.     case SILVER:
  1492.         score = SILVERPOINT;
  1493.         break;
  1494.     case GOLD:
  1495.         score = GOLDPOINT;
  1496.         break;
  1497.     case TELEPORT:
  1498.         iwhich = whichteleport(x, y);
  1499.         if (blocked(iwhich, orb[which].deltax, orb[which].deltay))
  1500.             orb[which].alive = FALSE;
  1501.         else
  1502.         {   effect(FXUSETELEPORT);
  1503.             score = TELPOINT;
  1504.             orb[which].x = xwrap(teleport[level][partner(iwhich)].x + orb[which].deltax);
  1505.             orb[which].y = ywrap(teleport[level][partner(iwhich)].y + orb[which].deltay);
  1506.         }
  1507.         break;
  1508.     case ORB:
  1509.         for (iwhich = 0; iwhich <= ORBS; iwhich++)
  1510.             if (iwhich != which && orb[iwhich].alive && x == orb[iwhich].x && y == orb[iwhich].y)
  1511.             {   effect(FXORBDEATH);
  1512.                 if (orb[iwhich].mode != ARMOUR)
  1513.                 {    orb[iwhich].alive = FALSE;
  1514.                     if (orb[which].mode != ARMOUR)
  1515.                         orb[which].alive = FALSE;
  1516.                     else effect(FXUSEARMOUR);
  1517.                 } else
  1518.                 {   orb[which].alive = FALSE;
  1519.                     if (orb[which].mode == ARMOUR)
  1520.                         orb[iwhich].alive = FALSE;
  1521.                     else effect(FXUSEARMOUR);
  1522.                 }
  1523.                 if (orb[which].alive && !orb[iwhich].alive)
  1524.                     score = orb[iwhich].score;
  1525.                 else if (!orb[which].alive && orb[iwhich].alive)
  1526.                     orb[iwhich].score += orb[which].score * orb[iwhich].multi;
  1527.                 else if (!orb[which].alive && !orb[iwhich].alive)
  1528.                 {    draw(x, y, BONUS);
  1529.                     field[x][y] = BONUS;
  1530.             }    }
  1531.         break;
  1532.     case FRAGMENT:
  1533.         whichfrag(x, y, &iwhich, &iiwhich);
  1534.         frag[iwhich][iiwhich].alive = FALSE;
  1535.         if (orb[which].mode != ARMOUR)
  1536.             orb[which].explode = TRUE;
  1537.         else effect(FXUSEARMOUR);
  1538.         break;
  1539.     case SKULL:
  1540.         effect(FXGETSKULL);
  1541.         score = SKULLPOINT;
  1542.         break;
  1543.     case SLIME:
  1544.         if (orb[which].mode != TONGUE)
  1545.             orb[which].alive = FALSE;
  1546.         break;
  1547.     default:
  1548.         break;
  1549.     }
  1550.     orb[which].score += score * orb[which].multi;
  1551. }
  1552.  
  1553. // update field
  1554.  
  1555. if (orb[which].alive)
  1556. {    if (orb[which].mode == TONGUE)
  1557.         draw(orb[which].x, orb[which].y, ORBTONGUE);
  1558.     else if (orb[which].mode == ARMOUR)
  1559.         draw(orb[which].x, orb[which].y, ORBARMOUR);
  1560.     else
  1561.         draw(orb[which].x, orb[which].y, ORB);
  1562.     field[orb[which].x][orb[which].y] = ORB;
  1563. }
  1564. }
  1565.  
  1566. void orbsplit(SBYTE which)
  1567. {    ABOOL    available;
  1568.     SBYTE    copy = 0, iwhich, iiwhich;
  1569.  
  1570.     effect(FXORBSPLIT);
  1571.     for (iwhich = 0; iwhich <= ORBS; iwhich++)
  1572.     {    available = TRUE;
  1573.         for (iiwhich = 0; iiwhich <= 7; iiwhich++)
  1574.             if (frag[iwhich][iiwhich].alive)
  1575.                 available = FALSE;
  1576.         if (!orb[iwhich].alive && copy <= 3 && available)
  1577.         {    orb[iwhich].x = orb[which].x;
  1578.             orb[iwhich].y = orb[which].y;
  1579.             orb[iwhich].score = orb[which].score;
  1580.             orb[iwhich].armour = orb[which].armour;
  1581.             orb[iwhich].tongue = orb[which].tongue;
  1582.             orb[iwhich].mode = orb[which].mode;
  1583.             orb[iwhich].speed = orb[which].speed;
  1584.             orb[iwhich].explode = FALSE;
  1585.             orb[iwhich].multi = orb[which].multi;
  1586.             orb[iwhich].moved = FALSE;
  1587.             switch (copy)
  1588.             {
  1589.             case 0:
  1590.                 if (orb[which].deltax != -1 || orb[which].deltay != -1)
  1591.                 {    orb[iwhich].deltax = -1;
  1592.                     orb[iwhich].deltay = -1;
  1593.                     orb[iwhich].alive = TRUE;
  1594.                 }
  1595.                 break;
  1596.             case 1:
  1597.                 if (orb[which].deltax != 1 || orb[which].deltay != 1)
  1598.                 {    orb[iwhich].deltax = 1;
  1599.                     orb[iwhich].deltay = 1;
  1600.                     orb[iwhich].alive = TRUE;
  1601.                 }
  1602.                 break;
  1603.             case 2:
  1604.                 if (orb[which].deltax != 1 || orb[which].deltay != -1)
  1605.                 {    orb[iwhich].deltax = 1;
  1606.                     orb[iwhich].deltay = -1;
  1607.                     orb[iwhich].alive = TRUE;
  1608.                 }
  1609.                 break;
  1610.             case 3:
  1611.                 if (orb[which].deltax != -1 || orb[which].deltay != 1)
  1612.                 {    orb[iwhich].deltax = -1;
  1613.                     orb[iwhich].deltay = 1;
  1614.                     orb[iwhich].alive = TRUE;
  1615.                 }
  1616.                 break;
  1617.             default:
  1618.                 break;
  1619.             }
  1620.             copy++;
  1621. }    }    }
  1622.  
  1623. void orientworms(void)
  1624. {    SBYTE    player;
  1625.  
  1626.     for (player = lo; player <= hi; player++)
  1627.     {    worm[player].speed = SLOW;
  1628.         if (worm[player].lives)
  1629.             stat(player, SPEEDLINE);
  1630.         worm[player].moved = FALSE;
  1631.         worm[player].x = startx[level];
  1632.         worm[player].y = starty[level];
  1633.         switch (player)
  1634.         {
  1635.         case 0:
  1636.             worm[0].deltax = -1;
  1637.             worm[0].deltay = 0;
  1638.             break;
  1639.         case 1:
  1640.             worm[1].deltax = 1;
  1641.             worm[1].deltay = 0;
  1642.             break;
  1643.         case 2:
  1644.             worm[2].deltax = 0;
  1645.             worm[2].deltay = -1;
  1646.             break;
  1647.         case 3:
  1648.             worm[3].deltax = 0;
  1649.             worm[3].deltay = 1;
  1650.             break;
  1651.         default:
  1652.             break;
  1653. }   }   }
  1654.  
  1655. SBYTE partner(SBYTE which)
  1656. {    if (which % 2 == 0)
  1657.         return((SBYTE) (which + 1));
  1658.     else return((SBYTE) (which - 1));
  1659. }
  1660.  
  1661. /* NAME        putletter -- Put a letter onto the field
  1662. SYNOPSIS    void putletter(SBYTE player);
  1663. INPUTS        SBYTE player -
  1664.             0-3: player on whose behalf the letter is put on for
  1665.             -1: any letter
  1666. RESULT        none
  1667. NOTES        noletter -
  1668.             -2: if we found somewhere to put the letter
  1669.             player: if we didn't */
  1670.  
  1671. void putletter(SBYTE player)
  1672. {    SBYTE    count = 0, letter;
  1673.     SBYTE    i, x, y;
  1674.  
  1675.     do
  1676.     {    x = rand() % (FIELDX + 1);
  1677.         y = rand() % (FIELDY + 1);
  1678.     } while ((field[x][y] < FIRSTEMPTY || field[x][y] > LASTEMPTY) && (++count < PATIENCE));
  1679.     if (count < PATIENCE)
  1680.     {    noletter = -2;
  1681.         if (player != -1)
  1682.         {    for (i = 0; i <= LETTERS; i++)
  1683.                 if (!(letters[player][i]))
  1684.                 {    break;
  1685.                 }
  1686.             if (i > LETTERS)
  1687.                 letter = rand() % (LETTERS + 1);
  1688.             else
  1689.             {    do
  1690.                     letter = rand() % (LETTERS + 1);
  1691.                 while (letters[player][letter]);
  1692.             }
  1693.         } else
  1694.             letter = rand() % (LETTERS + 1);
  1695.         field[x][y] = letter + FIRSTLETTER;
  1696.         draw(x, y, letter + FIRSTLETTER);
  1697.     } else noletter = player;
  1698. }
  1699.  
  1700. /* NAME     queue -- adds a keystroke to the key queue
  1701. SYNOPSIS    name(SBYTE, SBYTE, SBYTE);
  1702. FUNCTION    Adds a keystroke to the in-game key queue.
  1703. INPUTS      player - player that pressed the key
  1704.             deltax - the deltax of the key
  1705.             deltay - the deltay of the key
  1706. IMPLEMENTATION
  1707.             thequeue[] is an array, with QUEUELIMIT as its last index.
  1708.             It is implemented as a FIFO stack rather than LIFO so that
  1709.             the keystrokes are processed in the correct order (that is,
  1710.             the order in which they were pressed). The oldest keystroke
  1711.             is always at index [0], the next oldest at [1], and so on
  1712.             upwards to the newest keystroke, at [worm[player].pos].
  1713.             Keystrokes are removed from the bottom of the array ([0]),
  1714.             and the rest of the array is shuffled down to fill the gap,
  1715.             so that the contents of [1] go to [0], the contents of [2]
  1716.             go to [1], etc. worm[player].pos is adjusted to always point
  1717.             to the newest entry, which is the 'end' of the queue.
  1718. MODULE      engine.c */
  1719.  
  1720. void queue(SBYTE player, SBYTE deltax, SBYTE deltay)
  1721. {   if (worm[player].pos < QUEUELIMIT)
  1722.     {    worm[player].pos++;
  1723.         thequeue[player][worm[player].pos].deltax = deltax;
  1724.         thequeue[player][worm[player].pos].deltay = deltay;
  1725. }    }
  1726.  
  1727. void reflect(SBYTE which, SBYTE iwhich)
  1728. {    frag[which][iwhich].deltax = -frag[which][iwhich].deltax;
  1729.     frag[which][iwhich].deltay = -frag[which][iwhich].deltay;
  1730. }
  1731.  
  1732. void renderboard(void)
  1733. {    SBYTE    i, x, y;
  1734.  
  1735.     timeronoff(FALSE);
  1736.  
  1737.     switch(rand() % 3) {
  1738.     case 0:
  1739.         // chequered
  1740.         for (y = 0; y <= FIELDY; y += 2)
  1741.             for (x = 0; x <= FIELDX; x += 2)
  1742.                 draw(x, y, board[level][x][y]);
  1743.         for (x = 1; x <= FIELDX; x += 2)
  1744.             for (y = 1; y <= FIELDY; y += 2)
  1745.                 draw(x, y, board[level][x][y]);
  1746.         for (y = 0; y <= FIELDY; y += 2)
  1747.             for (x = 1; x <= FIELDX; x += 2)
  1748.                 draw(x, y, board[level][x][y]);
  1749.         for (x = 0; x <= FIELDX; x += 2)
  1750.             for (y = 1; y <= FIELDY; y += 2)
  1751.                 draw(x, y, board[level][x][y]);
  1752.         break;
  1753.     case 1:
  1754.         // `closing sliding doors'
  1755.         for (x = 0; x <= FIELDX / 2; x++)
  1756.             for (y = 0; y <= FIELDY; y++)
  1757.             {    draw(x, y, board[level][x][y]);
  1758.                 draw(FIELDX - x, y, board[level][x][y]);
  1759.             }
  1760.         break;
  1761.     case 2:
  1762.         // triangle
  1763.         for (i = 0; i <= FIELDY; i++)
  1764.             for (y = 0; y <= i; y++)
  1765.             {    draw(i, y, board[level][i][y]);
  1766.                 draw(y, i, board[level][y][i]);
  1767.             }
  1768.         for (i = FIELDY + 1; i <= FIELDX; i++)
  1769.             for (y = 0; y <= FIELDY; y++)
  1770.                 draw(i, y, board[level][i][y]);
  1771.         break;
  1772.     default:
  1773.         break;
  1774.     }
  1775.  
  1776.     timeronoff(TRUE);
  1777.     if (a == FIELDEDIT)
  1778.     {    draw(startx[level], starty[level], START);
  1779.         if (teleport[level][0].alive)
  1780.         {    draw(teleport[level][0].x, teleport[level][0].y, ONE);
  1781.             draw(teleport[level][1].x, teleport[level][1].y, TWO);
  1782. }    }    }
  1783.  
  1784. ABOOL savefields(STRPTR fieldname)
  1785. {    SBYTE    i, j;
  1786.     TEXT    IOBuffer[NAMELENGTH + 1];
  1787.  
  1788.     matchteleports();
  1789.  
  1790.     if (!ZOpen(fieldname, TRUE))
  1791.         return FALSE;
  1792.  
  1793.     // write header
  1794.  
  1795.     strcpy(IOBuffer,                    "FSET 4.1");
  1796.     IOBuffer[9]                            = levels;
  1797.     if (!ZWrite(IOBuffer, 10))
  1798.     {   ZClose();
  1799.         return FALSE;
  1800.     }
  1801.  
  1802.     // write high score table
  1803.  
  1804.     for (i = 0; i <= HISCORES; i++)
  1805.     {    IOBuffer[0]                        =  hiscore[i].player;
  1806.         IOBuffer[1]                        =  hiscore[i].level;
  1807.         IOBuffer[2]                        =  0;
  1808.         IOBuffer[3]                        =  hiscore[i].score / 65536;
  1809.         IOBuffer[4]                        = (hiscore[i].score % 65536) / 256;
  1810.         IOBuffer[5]                        = (hiscore[i].score % 65536) % 256;
  1811.         if (!ZWrite(IOBuffer, 6))
  1812.         {   ZClose();
  1813.             return FALSE;
  1814.         }
  1815.  
  1816.         for (j = 0; j <= NAMELENGTH; j++)
  1817.             IOBuffer[j]                    = hiscore[i].name[j];
  1818.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  1819.         {   ZClose();
  1820.             return FALSE;
  1821.     }    }
  1822.  
  1823.     // write level data
  1824.  
  1825.     for (i = 0; i <= levels; i++)
  1826.     {   IOBuffer[0]                        = startx[i];
  1827.         IOBuffer[1]                        = starty[i];
  1828.         IOBuffer[2]                        = teleport[i][0].alive;
  1829.         IOBuffer[3]                        = teleport[i][0].x;
  1830.         IOBuffer[4]                        = teleport[i][0].y;
  1831.         IOBuffer[5]                        = teleport[i][1].alive;
  1832.         IOBuffer[6]                        = teleport[i][1].x;
  1833.         IOBuffer[7]                        = teleport[i][1].y;
  1834.         if (!ZWrite(IOBuffer, 8))
  1835.         {   ZClose();
  1836.             return FALSE;
  1837.         }
  1838.  
  1839.         if (!ZWrite((char *) &board[i][0][0], (FIELDX + 1) * (FIELDY + 1)))
  1840.         {   ZClose();
  1841.             return FALSE;
  1842.     }    }
  1843.  
  1844.     // write version string
  1845.  
  1846.     if (!ZWrite(VERSION, strlen(VERSION)))
  1847.     {   ZClose();
  1848.         return FALSE;
  1849.     }
  1850.  
  1851.     ZClose();
  1852.  
  1853.     if (clearthem)
  1854.         clearhiscores();
  1855.     modified = FALSE;
  1856.     return TRUE;
  1857. }
  1858.  
  1859. void saylevel(COLOUR colour)
  1860. {    TEXT mainstring[15] = "Level ", tempstring[4];
  1861.  
  1862.     if (level > 0)
  1863.     {    stci_d(&mainstring[6], level);
  1864.         strcat((char*) mainstring, " of ");
  1865.         stci_d(tempstring, levels);
  1866.         strcat((char*) mainstring, (char*) tempstring);
  1867.         say(mainstring, colour);
  1868.     } else say((STRPTR) "Treasury", colour);
  1869. }
  1870.  
  1871. void setbrush(SBYTE newbrush)
  1872. {    brush = newbrush;
  1873.     setpointer(brush);
  1874.     underline(brush);
  1875. }
  1876.  
  1877. SBYTE slowdown(SBYTE speed, ABOOL nitro)
  1878. {    speed *= 2;
  1879.     if (nitro)
  1880.     {    if (speed > VERYSLOW)
  1881.             speed = VERYSLOW;
  1882.     } else if (speed > SLOW)
  1883.         speed = SLOW;
  1884.     return(speed);
  1885. }
  1886.  
  1887. /* NAME     slowloop -- things done rarely
  1888. SYNOPSIS    slowloop(void);
  1889. FUNCTION    Decrements strength; creates killers, orbs, objects,
  1890.             teleports, slime; controls timebombs; puts letters if
  1891.             neccessary; blanks out old causes.
  1892. MODULE      engine.c */
  1893.  
  1894. void slowloop(void)
  1895. {    ABOOL    available, done;
  1896.     SBYTE    i, iwhich, player, which, x, xx, y, yy;
  1897.  
  1898. // decrement strength
  1899.  
  1900. for (player = lo; player <= hi; player++)
  1901.     if (worm[player].lives > 0 && ice == -1 || ice == player)
  1902.     {    if (worm[player].bias > 0)
  1903.         {    worm[player].bias--;
  1904.             stat(player, BIASLINE);
  1905.         }
  1906.         if (worm[player].ice > 0 && --worm[player].ice == 0)
  1907.         {    for (which = lo; which <= hi; which++)
  1908.                 if (player != which)
  1909.                     worm[player].pos = -1;
  1910.             ice = -1;
  1911.         }
  1912.         if (worm[player].mode == ARMOUR)
  1913.         {    if (--worm[player].armour == 0)
  1914.             {    if (worm[player].tongue > 0)
  1915.                     worm[player].mode = TONGUE;
  1916.                 else worm[player].mode = NULL;
  1917.             }
  1918.             stat(player, ARMOURLINE);
  1919.         } else if (worm[player].mode == TONGUE)
  1920.         {    if (--worm[player].tongue == 0)
  1921.             {    if (worm[player].armour > 0)
  1922.                     worm[player].mode = ARMOUR;
  1923.                 else worm[player].mode = NULL;
  1924.             }
  1925.             stat(player, TONGUELINE);
  1926.     }    }
  1927.  
  1928. if (ice == -1)
  1929. {    for (which = 0; which <= ORBS; which++)
  1930.         if (orb[which].alive)
  1931.             if (orb[which].mode == ARMOUR)
  1932.             {    if (--orb[which].armour == 0)
  1933.                     if (orb[which].tongue > 0)
  1934.                         orb[which].mode = TONGUE;
  1935.                     else orb[which].mode = NULL;
  1936.             } else if (orb[which].mode == TONGUE)
  1937.             {    if (--orb[which].tongue == 0)
  1938.                     if (orb[which].armour > 0)
  1939.                         orb[which].mode = ARMOUR;
  1940.                     else orb[which].mode = NULL;
  1941.             }
  1942.  
  1943.     // create killers
  1944.  
  1945.     for (which = 0; which <= KILLERS; which++)
  1946.         if (!killer[which].alive && !(rand() % killerfreq) && findempty(&x, &y, FIRSTKILLER, LASTKILLER) && field[x][y] != KILLER)
  1947.         {    effect(FXKILLERBORN);
  1948.             killer[which].x = x;
  1949.             killer[which].y = y;
  1950.             killer[which].alive = TRUE;
  1951.             killer[which].last = field[killer[which].x][killer[which].y];
  1952.             field[killer[which].x][killer[which].y] = KILLER;
  1953.             draw(killer[which].x, killer[which].y, KILLER);
  1954.         }
  1955.  
  1956.     // create orbs
  1957.  
  1958.     for (which = 0; which <= ORBS; which++)
  1959.         if (!orb[which].alive && !(rand() % orbfreq))
  1960.         {    orb[which].x = rand() % (FIELDX + 1);
  1961.             orb[which].y = rand() % (FIELDY + 1);
  1962.             available = TRUE;
  1963.             for (iwhich = 0; iwhich <= 7; iwhich++)
  1964.                 if (frag[which][iwhich].alive)
  1965.                     available = FALSE;
  1966.             if (available && field[orb[which].x][orb[which].y] >= FIRSTEMPTY && field[orb[which].x][orb[which].y] <= LASTEMPTY)
  1967.             {    orb[which].deltax = (rand() % 2) * 2 - 1;
  1968.                 orb[which].deltay = (rand() % 2) * 2 - 1;
  1969.                 if (field[orb[which].x + orb[which].deltay][orb[which].y + orb[which].deltay] >= FIRSTEMPTY && field[orb[which].x + orb[which].deltax][orb[which].y + orb[which].deltay] <= LASTEMPTY)
  1970.                 {    effect(FXORBBORN);
  1971.                     orb[which].score = 0;
  1972.                     orb[which].alive = TRUE;
  1973.                     orb[which].armour = 0;
  1974.                     orb[which].tongue = 0;
  1975.                     orb[which].mode = NULL;
  1976.                     orb[which].speed = orbspeed;
  1977.                     orb[which].explode = FALSE;
  1978.                     orb[which].multi = 1;
  1979.                     orb[which].moved = FALSE;
  1980.         }    }    }
  1981.  
  1982.     // create objects
  1983.  
  1984.     for (which = 0; which <= LASTOBJECT; which++)
  1985.         if (!(rand() % object[which].frequency) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  1986.         {    field[x][y] = which;
  1987.             draw(x, y, which);
  1988.         }
  1989.  
  1990.     // create teleports
  1991.  
  1992.     if (!(rand() % TELFREQ)
  1993.     && !teleport[level][2].alive
  1994.     && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FIRSTEMPTY, LASTEMPTY)
  1995.     && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FIRSTEMPTY, LASTEMPTY)
  1996.     && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
  1997.     {    teleport[level][2].alive = TRUE;
  1998.         field[teleport[level][2].x][teleport[level][2].y] = TELEPORT;
  1999.         draw(teleport[level][2].x, teleport[level][2].y, TELEPORT);
  2000.         teleport[level][3].alive = TRUE;
  2001.         field[teleport[level][3].x][teleport[level][3].y] = TELEPORT;
  2002.         draw(teleport[level][3].x, teleport[level][3].y, TELEPORT);
  2003.     }
  2004.  
  2005.     // create timebombs
  2006.  
  2007.     for (i = 0; i <= level; i++)
  2008.     {    x = rand() % (FIELDX + 1);
  2009.         y = rand() % (FIELDY + 1);
  2010.         if (field[x][y] == BOMB)
  2011.         {    done = FALSE;
  2012.             for (which = 0; which <= TIMEBOMBS; which++)
  2013.                 if (timebomb[which].alive == FALSE && !done)
  2014.                 {    timebomb[which].alive = TRUE;
  2015.                     timebomb[which].x = x;
  2016.                     timebomb[which].y = y;
  2017.                     timebomb[which].time = 10;
  2018.                     done = TRUE;
  2019.     }    }        }
  2020.  
  2021.     // decrement and explode timebombs
  2022.  
  2023.     if (!(r % (VERYSLOW * TIMEBOMBSPEED)))
  2024.         for (which = 0; which <= TIMEBOMBS; which++)
  2025.             if (timebomb[which].alive)
  2026.             {    if (field[timebomb[which].x][timebomb[which].y] != BOMB)
  2027.                     timebomb[which].alive = FALSE;
  2028.                 else
  2029.                 {    effect(FXTIMEBOMBTICK);
  2030.                     timebomb[which].time--;
  2031.                     if (timebomb[which].time < 0)
  2032.                     {    timebomb[which].alive = FALSE;
  2033.                         field[timebomb[which].x][timebomb[which].y] = EMPTY;
  2034.                         draw(timebomb[which].x, timebomb[which].y, EMPTY);
  2035.                         bombblast(BOMB, 0, timebomb[which].x, timebomb[which].y);
  2036.                     } else draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
  2037.             }    }
  2038.  
  2039.     // create slime
  2040.     
  2041.     if (!(rand() % slimefreq))
  2042.     {    if (findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2043.         {    field[x][y] = SLIME;
  2044.             draw(x, y, SLIME);
  2045.     }    }
  2046.  
  2047.     // grow slime
  2048.  
  2049.     if (!(rand() % slimegrowfreq))
  2050.     {    for (x = 0; x <= FIELDX; x++)
  2051.             for (y = 0; y <= FIELDY; y++)
  2052.                 if (field[x][y] == SLIME)
  2053.                     for (xx = x - 1; xx <= x + 1; xx++)
  2054.                         for (yy = y - 1; yy <= y + 1; yy++)
  2055.                             if (valid(xx, yy) && field[xx][yy] == EMPTY && !(rand() % 2))
  2056.                                 field[xx][yy] = TEMPSLIME;
  2057.         for (x = 0; x <= FIELDX; x++)
  2058.             for (y = 0; y <= FIELDY; y++)
  2059.                 if (field[x][y] == TEMPSLIME)
  2060.                 {    field[x][y] = SLIME;
  2061.                     draw(x, y, SLIME);
  2062.     }            }
  2063.             
  2064.     // retry putting letters if necessary
  2065.  
  2066.     if (noletter != -2)
  2067.         putletter(noletter);
  2068. }
  2069.  
  2070. // blank out old causes
  2071.  
  2072. for (player = lo; player <= hi; player++)
  2073. {    if (worm[player].lives > 0 && r > worm[player].causewait)
  2074.     {    drawcause(player, BLACK);
  2075.         worm[player].causewait = (ULONG) -1; // most future time possible
  2076. }    }
  2077. }
  2078.  
  2079. SBYTE speedup(SBYTE speed, ABOOL nitro)
  2080. {    speed /= 2;
  2081.     if (nitro)
  2082.     {    if (speed < VERYFAST)
  2083.             speed = VERYFAST;
  2084.     } else if (speed < FAST)
  2085.         speed = FAST;
  2086.     return(speed);
  2087. }
  2088.  
  2089. LONG squareblast(SBYTE type, SBYTE player, SBYTE thissy, SBYTE x, SBYTE y)
  2090. {    SBYTE    iwhich, which;
  2091.     LONG    score = 0L;
  2092.     
  2093.     if (thissy <= LASTOBJECT)
  2094.     {    field[x][y] = EMPTY;
  2095.         draw(x, y, EMPTY);
  2096.         if (thissy == BOMB)
  2097.             for (which = 0; which <= TIMEBOMBS; which++)
  2098.                 if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
  2099.                     timebomb[which].alive = FALSE;
  2100.     } else if (thissy >= FIRSTTAIL) // assumes && thissy <= LASTTAIL
  2101.     {    draw(x, y, EMPTY);
  2102.         field[x][y] = EMPTY;
  2103.     } else if (thissy == ORB)
  2104.     {    which = whichorb(x, y);
  2105.         if (orb[which].mode != ARMOUR)
  2106.         {   effect(FXORBDEATH);
  2107.             orb[which].alive = FALSE;
  2108.             score = orb[which].score;
  2109.             if (type == HEAD && worm[player].bias)
  2110.                  worm[player].lives += ORBBLOOD;
  2111.             draw(x, y, BONUS);
  2112.             field[x][y] = BONUS;
  2113.         } else effect(FXUSEARMOUR);
  2114.     } else if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2115.     {    if (type != HEAD || player != thissy - FIRSTHEAD)
  2116.             if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2117.             {    worm[thissy - FIRSTHEAD].cause = BOMB;
  2118.                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2119.                 stat(thissy - FIRSTHEAD, LIVESLINE);
  2120.                 if (type == HEAD)
  2121.                     worm[thissy - FIRSTHEAD].victor = player;
  2122.                 else
  2123.                 {    worm[thissy - FIRSTHEAD].victor = -1;
  2124.                     score = KILLWORM; // worms will get thissy bonus from death(), so it is not given for them here.
  2125.                 }
  2126.             } else effect(FXUSEARMOUR);
  2127.     } else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2128.     {    if (type != HEAD || player != thissy - FIRSTMISSILE)
  2129.         {   stopfx(missile[thissy - FIRSTMISSILE].receipt);
  2130.             missile[thissy - FIRSTMISSILE].alive = FALSE;
  2131.             draw(x, y, EMPTY);
  2132.             field[x][y] = EMPTY;
  2133.     }    }
  2134.     else if (thissy == FRAGMENT)
  2135.     {    whichfrag(x, y, &which, &iwhich);
  2136.         frag[which][iwhich].alive = FALSE;
  2137.         draw(x, y, EMPTY);
  2138.         field[x][y] = EMPTY;
  2139.     } else if (thissy == KILLER)
  2140.     {    which = whichkiller(x, y);
  2141.         killer[which].alive = FALSE;
  2142.         draw(x, y, BONUS);
  2143.         field[x][y] = BONUS;
  2144.     }
  2145.     return(score);
  2146. }
  2147.  
  2148. void timeloop(void)
  2149. {
  2150. TEXT timedisplay[5] = {"#:##"};
  2151.  
  2152. if (secondsleft < 0L)
  2153.     secondsleft = 0L;
  2154. timedisplay[0] = 48 + (secondsleft / 60);
  2155. timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  2156. timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  2157. if (!level)
  2158. {    say(timedisplay, worm[treasurer].colour);
  2159.     if (!secondsleft)
  2160.     {    level = reallevel + 1;
  2161.         secondsleft = SECONDSPERLEVEL;
  2162.         newlevel(treasurer);
  2163. }    }
  2164. else if (!secondsleft)
  2165. {    if (outoftime == 1)
  2166.     {    fragspeed    = speedup(fragspeed,    TRUE);
  2167.         orbspeed    = speedup(orbspeed,        TRUE);
  2168.         killerspeed    = speedup(killerspeed,    TRUE);
  2169.         killerfreq /= 2;
  2170.         if (killerfreq < KILLERFREQEND)
  2171.                killerfreq = KILLERFREQEND;
  2172.         orbfreq /= 2;
  2173.         if (orbfreq < ORBFREQEND)
  2174.                orbfreq = ORBFREQEND;
  2175.         slimefreq /= 2;
  2176.         if (slimefreq < SLIMEFREQEND)
  2177.             slimefreq = SLIMEFREQEND;
  2178.         slimegrowfreq /= 2;
  2179.         if (slimegrowfreq < SLIMEGROWFREQEND)
  2180.             slimegrowfreq = SLIMEGROWFREQEND;
  2181.         outoftime = 2;
  2182.     }
  2183.     say(timedisplay, LIGHTGREY);
  2184. } else if (secondsleft <= 10)
  2185. {    if (outoftime == 0)
  2186.     {    effect(FXTIMEALERT);
  2187.         outoftime = 1;
  2188.     }
  2189.     say(timedisplay, RED);
  2190. } else if (secondsleft <= 20)
  2191.     say(timedisplay, YELLOW);
  2192. else say(timedisplay, GREEN);
  2193. }
  2194.  
  2195. void train(SCANCODE scancode)
  2196. {    SBYTE i, x, y;
  2197.  
  2198.     switch(scancode) {
  2199.     case HELP:
  2200.         if (!trainer)
  2201.             trainer = TRUE;
  2202.         else trainer = FALSE;
  2203.         break;
  2204.     case NUMERICMINUS:
  2205.         // Fill most squares with empty.
  2206.         if (trainer)
  2207.         {    trainer = FALSE;
  2208.             for (x = 0; x <= FIELDX; x++)
  2209.                 for (y = 0; y <= FIELDY; y++)
  2210.                     if (field[x][y] != STONE && field[x][y] != KILLER && field[x][y] != ORB && field[x][y] != SKULL && (field[x][y] < FIRSTHEAD || field[x][y] > LASTHEAD) && (field[x][y] < FIRSTLETTER || field[x][y] > LASTLETTER))
  2211.                     {    draw(x, y, EMPTY);
  2212.                         field[x][y] = EMPTY;
  2213.         }            }
  2214.         break;
  2215.     case NUMERICSLASH:
  2216.         // Complete the level.
  2217.         if (trainer)
  2218.         {    trainer = FALSE;
  2219.             if (worm[1].lives > 0)
  2220.                 for (i = 0; i <= LETTERS; i++)
  2221.                     letters[1][i] = TRUE;
  2222.         }
  2223.         break;
  2224.     case NUMERICASTERISK:
  2225.         // Change most squares to gold.
  2226.         if (trainer)
  2227.         {    trainer = FALSE;
  2228.             for (x = 0; x <= FIELDX; x++)
  2229.                 for (y = 0; y <= FIELDY; y++)
  2230.                     if (field[x][y] != STONE && field[x][y] != KILLER && field[x][y] != ORB && field[x][y] != SKULL && (field[x][y] < FIRSTHEAD || field[x][y] > LASTHEAD) && (field[x][y] < FIRSTLETTER || field[x][y] > LASTLETTER))
  2231.                     {    draw(x, y, GOLD);
  2232.                         field[x][y] = GOLD;
  2233.         }            }
  2234.         break;
  2235.     case NUMERICPLUS:
  2236.         // Full lives, tongue, bias, ammo, power, nitro and affixer.
  2237.         if (trainer)
  2238.         {    trainer = FALSE;
  2239.             if (worm[1].lives > 0)
  2240.             {    worm[1].lives = LIVESLIMIT;
  2241.                 stat(1, LIVESLINE);
  2242.                 worm[1].tongue = MODELIMIT;
  2243.                 worm[1].mode = TONGUE;
  2244.                 stat(1, TONGUELINE);
  2245.                 worm[1].bias = BIASLIMIT;
  2246.                 stat(1, BIASLINE);
  2247.                 worm[1].ammo = AMMOLIMIT;
  2248.                 stat(1, AMMOLINE);
  2249.                 worm[1].power = POWERLIMIT;
  2250.                 stat(1, POWERLINE);
  2251.                 worm[1].nitro = TRUE;
  2252.                 stat(1, SPEEDLINE);
  2253.                 worm[1].affixer = TRUE;
  2254.                 trainer = FALSE;
  2255.         }    }
  2256.         break;
  2257.     default:
  2258.         break;
  2259. }    }
  2260.  
  2261. void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  2262. {
  2263. if (worm[player].nitro || !deltax || !deltay)
  2264. {    if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  2265.     {    worm[player].speed = speedup(worm[player].speed, worm[player].nitro);
  2266.         stat(player, SPEEDLINE);
  2267.     } else if (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  2268.     {    worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  2269.         stat(player, SPEEDLINE);
  2270.     } else
  2271.     {    worm[player].deltax = deltax;
  2272.         worm[player].deltay = deltay;
  2273. }    }
  2274. }
  2275.  
  2276. void updatesquare(SBYTE x, SBYTE y)
  2277. {    SBYTE    which;
  2278.  
  2279.     if (startx[level] == x && starty[level] == y)
  2280.         draw(x, y, START);
  2281.     else if (board[level][x][y] == TELEPORT)
  2282.     {    for (which = 0; which <= 1; which++)
  2283.             if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2284.                 draw(x, y, ONE + which);
  2285.     } else draw(x, y, board[level][x][y]);
  2286. }
  2287.  
  2288. SBYTE valid(SBYTE x, SBYTE y)
  2289. {    if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
  2290.         return(TRUE);
  2291.     else
  2292.         return(FALSE);
  2293. }
  2294.  
  2295. void whichfrag(SBYTE x, SBYTE y, SBYTE* whichptr, SBYTE* iwhichptr)
  2296. {    SBYTE which, iwhich;
  2297.  
  2298.     for (which = 0; which <= ORBS + 1; which++)
  2299.         for (iwhich = 0; iwhich <= 7; iwhich++)
  2300.             if (frag[which][iwhich].alive && frag[which][iwhich].x == x && frag[which][iwhich].y == y)
  2301.             {    *whichptr = which;
  2302.                 *iwhichptr = iwhich;
  2303.                 return;
  2304. }            }
  2305. SBYTE whichkiller(SBYTE x, SBYTE y)
  2306. {   SBYTE which;
  2307.  
  2308.     for (which = 0; which <= KILLERS; which++)
  2309.         if (killer[which].alive && killer[which].x == x && killer[which].y == y)
  2310.             return(which);
  2311.     return(-1); // error code
  2312. }
  2313. SBYTE whichorb(SBYTE x, SBYTE y)
  2314. {   SBYTE which;
  2315.  
  2316.     for (which = 0; which <= ORBS; which++)
  2317.         if (orb[which].alive && orb[which].x == x && orb[which].y == y)
  2318.             return(which);
  2319.     return(-1); // error code
  2320. }
  2321. SBYTE whichteleport(SBYTE x, SBYTE y)
  2322. {   SBYTE which;
  2323.  
  2324.     for (which = 0; which <= TIMEBOMBS; which++)
  2325.         if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2326.             return((SBYTE) which);
  2327.     return((SBYTE) -1); // error code
  2328. }
  2329. SBYTE whichtimebomb(SBYTE x, SBYTE y)
  2330. {   SBYTE which;
  2331.  
  2332.     for (which = 0; which <= TIMEBOMBS; which++)
  2333.         if (timebomb[which].alive && timebomb[which].x == x && timebomb[which].y == y)
  2334.             return(which);
  2335.     return(-1); // error code
  2336. }
  2337.  
  2338. void wormbullet(SBYTE player)
  2339. {    ABOOL    finished,
  2340.             flag,
  2341.             ok            = FALSE,
  2342.             lettered    = FALSE;
  2343.     LONG    score;
  2344.     SBYTE    distance,
  2345.             thissy,
  2346.             i, j, k,
  2347.             x, y;
  2348.  
  2349.     if (!worm[player].ammo)
  2350.     {    stat(player, SCORELINE);
  2351.         if (worm[player].speed == FAST)
  2352.             distance = FASTDISTANCE;
  2353.         else if (worm[player].speed == NORMAL)
  2354.             distance = NORMALDISTANCE;
  2355.         else if (worm[player].speed == SLOW)
  2356.             distance = SLOWDISTANCE;
  2357.         else if (worm[player].speed == VERYFAST)
  2358.             distance = VERYFASTDISTANCE;
  2359.         else distance = VERYSLOWDISTANCE;
  2360.         if (abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1)
  2361.         {   x = xwrap(worm[player].x + worm[player].deltax * distance);
  2362.             y = ywrap(worm[player].y + worm[player].deltay * distance);
  2363.             thissy = field[x][y];
  2364.             if (thissy == TELEPORT)
  2365.             {   i = whichteleport(x, y);
  2366.                 if (!blocked(i, worm[player].deltax, worm[player].deltay))
  2367.                     ok = TRUE;
  2368.             }
  2369.             if (ok || thissy < STONE || thissy > KILLER)
  2370.             {    flag = FALSE;
  2371.                 for (i = lo; i <= hi; i++)
  2372.                     if (worm[i].control == HUMAN)
  2373.                         flag = TRUE;
  2374.                 if (!flag || worm[player].control == HUMAN)
  2375.                     effect(FXJUMP);
  2376.                 // Amiga-worms only make jumping sounds in demo mode
  2377.                 worm[player].deltax *= distance;
  2378.                 worm[player].deltay *= distance;
  2379.     }    }    }
  2380.     else
  2381.     {    effect(FXSHOOT);
  2382.         worm[player].ammo--;
  2383.         stat(player, AMMOLINE);
  2384.         if (!missile[player].alive && worm[player].bias)
  2385.         {   missile[player].receipt = effect(FXMISSILEACTIVE);
  2386.             missile[player].alive = TRUE;
  2387.             missile[player].x = worm[player].x;
  2388.             missile[player].y = worm[player].y;
  2389.             missile[player].moved = FALSE;
  2390.         }
  2391.         for (i = 0; i <= worm[player].power; i++)
  2392.         {    bullet[i].alive = TRUE;
  2393.             bullet[i].teleported = 0;
  2394.             bullet[i].visible = TRUE;
  2395.             if (i % 2 == 0)
  2396.                 distance = i / 2;
  2397.             else
  2398.                 distance = -((i + 1) / 2);
  2399.             if (worm[player].deltax == 0)
  2400.             {    bullet[i].x = worm[player].x + distance;
  2401.                 bullet[i].y = worm[player].y + worm[player].deltay;
  2402.             } else if (worm[player].deltay == 0)
  2403.             {    bullet[i].x = worm[player].x + worm[player].deltay;
  2404.                 bullet[i].y = worm[player].y + distance;
  2405.             } else
  2406.             {    switch (i) {
  2407.                 case 0:
  2408.                    bullet[i].x = worm[player].x + worm[player].deltax;
  2409.                    bullet[i].y = worm[player].y + worm[player].deltay;
  2410.                    break;
  2411.                 case 1:
  2412.                    bullet[i].x = worm[player].x + worm[player].deltax;
  2413.                    bullet[i].y = worm[player].y;
  2414.                    break;
  2415.                 case 2:
  2416.                    bullet[i].x = worm[player].x;
  2417.                    bullet[i].y = worm[player].y + worm[player].deltay;
  2418.                    break;
  2419.                 case 3:
  2420.                    bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2421.                    bullet[i].y = worm[player].y;
  2422.                    break;
  2423.                 case 4:
  2424.                    bullet[i].x = worm[player].x;
  2425.                    bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2426.                    break;
  2427.                 case 5:
  2428.                    bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2429.                    bullet[i].y = worm[player].y - worm[player].deltay;
  2430.                    break;
  2431.                 case 6:
  2432.                    bullet[i].x = worm[player].x - worm[player].deltax;
  2433.                    bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2434.                    break;
  2435.                 default:
  2436.                    break;
  2437.             }    }
  2438.                if (!(valid(bullet[i].x, bullet[i].y)))
  2439.                    bullet[i].alive = FALSE;
  2440.         }
  2441.         score = 0L;
  2442.         finished = FALSE;
  2443.         while (!finished)
  2444.         {    finished = TRUE;
  2445.             for (i = 0; i <= worm[player].power; i++)
  2446.             {   if (bullet[i].alive)
  2447.                 {    finished = FALSE;
  2448.                     if (bullet[i].visible)
  2449.                         if (bullet[i].teleported)
  2450.                         {   if (worm[player].bias)
  2451.                             {    draw(bullet[i].x, bullet[i].y, GOLD);
  2452.                                 field[bullet[i].x][bullet[i].y] = GOLD;
  2453.                             } else
  2454.                             {    draw(bullet[i].x, bullet[i].y, SILVER);
  2455.                                 field[bullet[i].x][bullet[i].y] = SILVER;
  2456.                         }    }
  2457.                         else
  2458.                         {    draw(bullet[i].x, bullet[i].y, EMPTY);
  2459.                             field[bullet[i].x][bullet[i].y] = EMPTY;
  2460.                         }
  2461.                     else bullet[i].visible = TRUE;
  2462.                     bullet[i].x += worm[player].deltax;
  2463.                     bullet[i].y += worm[player].deltay;
  2464.                     if (!(valid(bullet[i].x, bullet[i].y)))
  2465.                         bullet[i].alive = FALSE;
  2466.                     else
  2467.                     {    thissy = field[bullet[i].x][bullet[i].y];
  2468.                         if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2469.                         {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2470.                             {    worm[thissy - FIRSTHEAD].cause = FIRSTFIRE + player;
  2471.                                 worm[thissy - FIRSTHEAD].victor = player;
  2472.                                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2473.                                 score += KILLWORM + HITSHOT;
  2474.                             } else effect(FXUSEARMOUR);
  2475.                             bullet[i].alive = FALSE;
  2476.                         } else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2477.                         {    if (player != thissy - FIRSTPROTECTOR)
  2478.                             {    effect(FXUSEPROTECTOR);
  2479.                                 bullet[i].alive = FALSE;
  2480.                             } else
  2481.                                 bullet[i].visible = FALSE;
  2482.                         } else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2483.                         {    if (player != thissy - FIRSTMISSILE)
  2484.                             {   stopfx(missile[thissy - FIRSTMISSILE].receipt);
  2485.                                 missile[thissy - FIRSTMISSILE].alive = FALSE;
  2486.                             } else bullet[i].visible = FALSE;
  2487.                         } else if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2488.                         {    wormletter(player, thissy);
  2489.                             lettered = TRUE;
  2490.                         } else
  2491.                         {    switch(thissy) {
  2492.                             case STONE:
  2493.                                 bullet[i].alive = FALSE;
  2494.                                 break;
  2495.                             case ORB:
  2496.                                 for (j = 0; j <= ORBS; j++)
  2497.                                    if (orb[j].alive && orb[j].x == bullet[i].x && orb[j].y == bullet[i].y)
  2498.                                    {   bullet[i].alive = FALSE;
  2499.                                        if (orb[j].mode != ARMOUR)
  2500.                                        {   orb[j].explode = TRUE;
  2501.                                            score += orb[j].score + HITSHOT;
  2502.                                            if (worm[player].bias)
  2503.                                                worm[player].lives += ORBBLOOD;
  2504.                                        } else effect(FXUSEARMOUR);
  2505.                                    }
  2506.                                 break;
  2507.                             case TELEPORT:
  2508.                                 j = whichteleport(bullet[i].x, bullet[i].y);
  2509.                                 if (bullet[i].teleported == 2)
  2510.                                     bullet[i].alive = FALSE;
  2511.                                 else
  2512.                                 {   effect(FXUSETELEPORT);
  2513.                                     bullet[i].visible = FALSE;
  2514.                                     bullet[i].teleported++;
  2515.                                     bullet[i].x = teleport[level][partner(j)].x;
  2516.                                     bullet[i].y = teleport[level][partner(j)].y;
  2517.                                     score += TELPOINT;
  2518.                                 }
  2519.                                 break;
  2520.                             case WOOD:
  2521.                                 if (!worm[player].bias)
  2522.                                     bullet[i].alive = FALSE;
  2523.                                 break;
  2524.                             case KILLER:
  2525.                                 for (j = 0; j <= KILLERS; j++)
  2526.                                     if (killer[j].alive && killer[j].x == bullet[i].x && killer[j].y == bullet[i].y)
  2527.                                     {   killer[j].alive = FALSE;
  2528.                                         draw(bullet[i].x, bullet[i].y, BONUS);
  2529.                                         field[bullet[i].x][bullet[i].y] = BONUS;
  2530.                                         score += KILLKILLER + HITSHOT;
  2531.                                         if (worm[player].bias)
  2532.                                             worm[player].lives += KILLERBLOOD;
  2533.                                        }
  2534.                                    bullet[i].alive = FALSE;
  2535.                                    break;
  2536.                                case SKULL:
  2537.                                    bullet[i].alive = FALSE;
  2538.                                    break;
  2539.                                case FRAGMENT:
  2540.                                    bullet[i].alive = FALSE;
  2541.                                    whichfrag(bullet[i].x, bullet[i].y, &j, &k);
  2542.                                    frag[j][k].alive = FALSE;
  2543.                                    field[bullet[i].x][bullet[i].y] = EMPTY;
  2544.                                    draw(bullet[i].x, bullet[i].y, EMPTY);
  2545.                                    break;
  2546.                                case BOMB:
  2547.                                    j = whichtimebomb(bullet[i].x, bullet[i].y);
  2548.                                    if (j != -1)
  2549.                                    {   bullet[i].alive = FALSE;
  2550.                                        timebomb[j].alive = FALSE;
  2551.                                        field[timebomb[j].x][timebomb[j].y] = EMPTY;
  2552.                                        draw(timebomb[j].x, timebomb[j].y, EMPTY);
  2553.                                        bombblast(HEAD, player, timebomb[j].x, timebomb[j].y);
  2554.                                    }
  2555.                                    break;
  2556.                                default:
  2557.                                    break;
  2558.                             }
  2559.                                if (bullet[i].alive && bullet[i].visible)
  2560.                                 draw(bullet[i].x, bullet[i].y, FIRSTFIRE + player);
  2561.         }    }    }    }    }
  2562.         if (lettered)
  2563.             putletter(player);
  2564.         wormscore(player, score);
  2565.         if (worm[player].bias)
  2566.             stat(player, LIVESLINE);
  2567.         clearkybd();
  2568. }    }
  2569.  
  2570. void wormletter(SBYTE player, SBYTE thissy)
  2571. {    if (thissy == GREEN_C)
  2572.         effect(FX_C);
  2573.     else if (thissy == RED_O)
  2574.         effect(FX_O);
  2575.     else if (thissy == BLUE_M)
  2576.         effect(FX_M);
  2577.     else if (thissy == YELLOW_P)
  2578.         effect(FX_P);
  2579.     else if (thissy == GREEN_L)
  2580.         effect(FX_L);
  2581.     else if (thissy == BLUE_T)
  2582.         effect(FX_T);
  2583.     else // assumes RED_E or YELLOW_E
  2584.         effect(FX_E);
  2585.     letters[player][thissy - FIRSTLETTER] = TRUE;
  2586.        drawletter(player, thissy, NORMAL);
  2587.     if (player == (thissy - FIRSTLETTER) % 4)
  2588.         wormscore(player, MYLETTER);
  2589.     else wormscore(player, YOURLETTER);
  2590. }
  2591.  
  2592. /* NAME     wormloop -- controls worms and protectors
  2593. SYNOPSIS    wormloop(SBYTE);
  2594. FUNCTION    Amiga-worm thinking, processing one keystroke from the
  2595.             worm's queue, all the worm's protectors' control, the
  2596.             worm's control.
  2597. MODULE      engine.c */
  2598.  
  2599. void wormloop(SBYTE player)
  2600. {
  2601. ABOOL    complete, done, flag;
  2602. SBYTE    bestgood, bestx, besty, creature, died, dirx, diry, good, i, ithis,
  2603.         iwhich, thissy, thisletter, thisprot = -1, which, x, xx, y, yy;
  2604. LONG    score = 0L;
  2605.  
  2606.     /* AI: Amiga worm control
  2607.  
  2608.     Worm checks ahead, left and right one square. Assigns opinions to those
  2609.     three choices and then takes the appropriate one.
  2610.     
  2611.     Possible enhancements:
  2612.         recognition of possession of objects
  2613.             (esp. ammo, nitro, tongue, armour)
  2614.         finer gradients of decision
  2615.             (eg. certain objects better than others)
  2616.         longer lookahead */
  2617.  
  2618.     if (worm[player].control == AMIGA)
  2619.     {    if (!(rand() % 200))
  2620.             queue(player, (rand() % 3) - 1, (rand() % 3) - 1);
  2621.         else
  2622.         {    bestgood = -128;
  2623.  
  2624.             for (i = 0; i <= 2; i++)
  2625.             {    switch(i) {
  2626.                 case 0:
  2627.                     dirx = worm[player].deltax;
  2628.                     diry = worm[player].deltay;
  2629.                     break;
  2630.                 case 1:
  2631.                     if (worm[player].deltax == 0)    // if going north or south
  2632.                     {    dirx = -1;                    // then look west
  2633.                         diry = 0;
  2634.                     } else                            // if going east or west
  2635.                     {    dirx = 0;                    // then look north
  2636.                         diry = -1;
  2637.                     }
  2638.                     break;
  2639.                 case 2:
  2640.                     if (worm[player].deltax == 0)    // if going north or south
  2641.                     {    dirx = 1;                    // then look east
  2642.                         diry = 0;
  2643.                     } else                            // if going east or west
  2644.                     {    dirx = 0;                    // then look south
  2645.                         diry = 1;
  2646.                     }
  2647.                     break;
  2648.                 default:
  2649.                     break;
  2650.                 }
  2651.                 thissy = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
  2652.                 if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2653.                     good = 100;
  2654.                 else if (thissy <= LASTOBJECT)
  2655.                     good = 80;
  2656.                 else if (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2657.                 {    if (player == thissy - FIRSTTAIL)
  2658.                         good = -30;
  2659.                     else good = -60;
  2660.                 } else switch(thissy) {
  2661.                 case SKULL:
  2662.                     good = 70;
  2663.                     break;
  2664.                 case GOLD:
  2665.                     good = 50;
  2666.                     break;
  2667.                 case SILVER:
  2668.                     good = 40;
  2669.                     break;
  2670.                 case EMPTY:
  2671.                     good = 10;
  2672.                     break;
  2673.                 case WOOD:
  2674.                     good = -80;
  2675.                     break;
  2676.                 case STONE:
  2677.                     good = -90;
  2678.                     break;
  2679.                 case KILLER:
  2680.                     good = -100;
  2681.                     break;
  2682.                 default:
  2683.                     good = -50; // slime, heads, orbs, etc.
  2684.                     break;
  2685.                 }
  2686.                 if (good > bestgood)
  2687.                 {    bestx = dirx;
  2688.                     besty = diry;
  2689.                     bestgood = good;
  2690.             }    }
  2691.  
  2692.             if (bestgood <= -60)
  2693.                 queue(player, 0, 0);
  2694.             else if (bestgood < 0 && (!(rand() % 2)))
  2695.                 queue(player, 0, 0);
  2696.             // Amiga worms are not allowed to go VERYFAST
  2697.             else if (bestx != worm[player].deltax || besty != worm[player].deltay || worm[player].speed > FAST)
  2698.                 queue(player, bestx, besty);
  2699.     }    }
  2700.  
  2701. // remove a keystroke from the queue
  2702.  
  2703. if (worm[player].pos != -1)
  2704. {   if (thequeue[player][0].deltax == 0 && thequeue[player][0].deltay == 0)
  2705.         wormbullet(player);
  2706.     else turnworm(player, thequeue[player][0].deltax, thequeue[player][0].deltay);
  2707.     if (--worm[player].pos != -1)
  2708.         for (i = 0; i <= worm[player].pos; i++)
  2709.         {   thequeue[player][i].deltax = thequeue[player][i + 1].deltax;
  2710.             thequeue[player][i].deltay = thequeue[player][i + 1].deltay;
  2711. }       }
  2712.  
  2713. // move worm
  2714.  
  2715. field[worm[player].x][worm[player].y] = worm[player].last;
  2716. draw(worm[player].x, worm[player].y, worm[player].last);
  2717. worm[player].x = xwrap(worm[player].x + worm[player].deltax);
  2718. worm[player].y = ywrap(worm[player].y + worm[player].deltay);
  2719. worm[player].deltax = bsign(worm[player].deltax);
  2720. worm[player].deltay = bsign(worm[player].deltay);
  2721. worm[player].last = FIRSTTAIL + player;
  2722.  
  2723. // move protectors
  2724.  
  2725. for (which = 0; which <= PROTECTORS; which++)
  2726. {   if (protector[player][which].alive)
  2727.     {   if (protector[player][which].visible)
  2728.         {   draw(protector[player][which].x, protector[player][which].y, protector[player][which].last);
  2729.             field[protector[player][which].x][protector[player][which].y] = protector[player][which].last;
  2730.         } else protector[player][which].visible = TRUE;
  2731.         protector[player][which].last = EMPTY;
  2732.  
  2733.         if (which == NOSE)
  2734.         {    protector[player][which].relx = worm[player].deltax * NOSEDISTANCE;
  2735.             protector[player][which].rely = worm[player].deltay * NOSEDISTANCE;
  2736.             if (!worm[player].affixer)
  2737.             {    if (worm[player].position == -1)
  2738.                     worm[player].posidir = 1;
  2739.                 else if (worm[player].position == 1)
  2740.                     worm[player].posidir = -1;
  2741.                 worm[player].position += worm[player].posidir;
  2742.                 if (worm[player].deltax == 0)
  2743.                     protector[player][which].relx = worm[player].position;
  2744.                 else if (worm[player].deltay == 0)
  2745.                     protector[player][which].rely = worm[player].position;
  2746.                 else if (worm[player].position == -1)
  2747.                     protector[player][which].relx = worm[player].deltax * (NOSEDISTANCE - 1);
  2748.                 else if (worm[player].position == 1)
  2749.                     protector[player][which].rely = worm[player].deltay * (NOSEDISTANCE - 1);
  2750.         }    }
  2751.         else if (!worm[player].affixer)
  2752.         {    if (protector[player][which].relx == 1 && protector[player][which].rely == -1)
  2753.             {    protector[player][which].deltax = 0;
  2754.                 protector[player][which].deltay = 1;
  2755.             } else if (protector[player][which].relx == 1 && protector[player][which].rely == 1)
  2756.             {    protector[player][which].deltax = -1;
  2757.                 protector[player][which].deltay = 0;
  2758.             } else if (protector[player][which].relx == -1 && protector[player][which].rely == 1)
  2759.             {    protector[player][which].deltax = 0;
  2760.                 protector[player][which].deltay = -1;
  2761.             } else if (protector[player][which].relx == -1 && protector[player][which].rely == -1)
  2762.             {    protector[player][which].deltax = 1;
  2763.                 protector[player][which].deltay = 0;
  2764.             }
  2765.             protector[player][which].relx += protector[player][which].deltax;
  2766.             protector[player][which].rely += protector[player][which].deltay;
  2767.         }
  2768.         protector[player][which].x = worm[player].x + protector[player][which].relx;
  2769.         protector[player][which].y = worm[player].y + protector[player][which].rely;
  2770.         if (!valid(protector[player][which].x, protector[player][which].y))
  2771.             protector[player][which].visible = FALSE;
  2772. }    }
  2773.  
  2774. // collision detection
  2775.  
  2776. creature = HEAD;
  2777. while (creature != NULL)
  2778. {    if (creature == HEAD)
  2779.     {   x = worm[player].x;
  2780.         y = worm[player].y;
  2781.     } else
  2782.     {    x = protector[player][thisprot].x;
  2783.         y = protector[player][thisprot].y;
  2784.     }
  2785.     thissy = field[x][y];
  2786.     if (creature == HEAD)
  2787.     {   if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2788.         {   died = 0;
  2789.             if (worm[thissy - FIRSTHEAD].mode != TONGUE)
  2790.             {   worm[thissy - FIRSTHEAD].cause = FIRSTHEAD + player;
  2791.                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2792.                 worm[thissy - FIRSTHEAD].victor = player;
  2793.                 died++;
  2794.             }
  2795.             if (worm[player].mode != TONGUE)
  2796.             {   worm[player].cause = thissy;
  2797.                 worm[player].alive = FALSE;
  2798.                 worm[player].victor = thissy - FIRSTHEAD;
  2799.                 died++;
  2800.             }
  2801.             if (died == 0)
  2802.             {   worm[thissy - FIRSTHEAD].score += CROSSHEADS * worm[thissy - FIRSTHEAD].multi;
  2803.                 score += CROSSHEADS;
  2804.             } else if (died == 2)
  2805.             {   worm[thissy - FIRSTHEAD].victor = -1;
  2806.                 worm[player].victor = -1;
  2807.         }   }
  2808.         else if (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2809.         {   if (worm[player].mode == TONGUE)
  2810.             {   if (!worm[player].tonguereceipt)
  2811.                     worm[player].tonguereceipt = effect(FXUSETONGUE);
  2812.                 if (lo != hi)
  2813.                     if (player == thissy - FIRSTTAIL)
  2814.                     {   score += TURNTOSILVER;
  2815.                         worm[player].last = SILVER;
  2816.                     } else
  2817.                     {   score += TURNTOGOLD;
  2818.                         worm[player].last = GOLD;
  2819.             }       }
  2820.             else
  2821.             {   worm[player].cause = thissy;
  2822.                 worm[player].alive = FALSE;
  2823.                 worm[player].victor = thissy - FIRSTTAIL;
  2824.         }   }
  2825.         else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2826.             if (worm[player].mode != ARMOUR)
  2827.             {   worm[player].cause = thissy;
  2828.                 worm[player].victor = thissy - FIRSTPROTECTOR;
  2829.                 worm[player].alive = FALSE;
  2830.             } else effect(FXUSEARMOUR);
  2831.         else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2832.         {   if (player != thissy - FIRSTMISSILE)
  2833.             {   stopfx(missile[thissy - FIRSTMISSILE].receipt);
  2834.                 missile[thissy - FIRSTMISSILE].alive = FALSE;
  2835.                 if (worm[player].mode != ARMOUR)
  2836.                 {   worm[player].alive = FALSE;
  2837.                     worm[player].cause = thissy;
  2838.                     worm[player].victor = thissy - FIRSTMISSILE;
  2839.                 } else effect(FXUSEARMOUR);
  2840.         }   }
  2841.         else if (thissy == STONE || thissy == KILLER)
  2842.         {   worm[player].cause = thissy;
  2843.             worm[player].victor = -1;
  2844.             worm[player].alive = FALSE;
  2845.             worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  2846.             worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  2847.         } else if (thissy == WOOD)
  2848.         {   if (worm[player].mode != TONGUE)
  2849.             {   worm[player].cause = WOOD;
  2850.                 worm[player].alive = FALSE;
  2851.                 worm[player].victor = -1;
  2852.         }   }
  2853.         else if (thissy == SLIME)
  2854.         {    if (worm[player].mode != ARMOUR)
  2855.             {    worm[player].cause = SLIME;
  2856.                 worm[player].alive = FALSE;
  2857.                 worm[player].victor = -1;
  2858.         }    }
  2859.         else if (thissy == TELEPORT)
  2860.         {   which = whichteleport(x, y);
  2861.             if (blocked(which, worm[player].deltax, worm[player].deltay))
  2862.             {   worm[player].cause = TELEPORT;
  2863.                 worm[player].victor = -1;
  2864.                 worm[player].alive = FALSE;
  2865.                 worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  2866.                 worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  2867.             } else
  2868.             {   effect(FXUSETELEPORT);
  2869.                 score += TELPOINT;
  2870.                 worm[player].x = xwrap(teleport[level][partner(which)].x + worm[player].deltax);
  2871.                 worm[player].y = ywrap(teleport[level][partner(which)].y + worm[player].deltay);
  2872.     }   }   }
  2873.     else // creature == PROTECTOR
  2874.     {   if (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2875.         {   if (player != thissy - FIRSTHEAD)
  2876.             {    if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2877.                 {   effect(FXUSEPROTECTOR);
  2878.                     worm[thissy - FIRSTHEAD].cause = FIRSTPROTECTOR + player;
  2879.                     worm[thissy - FIRSTHEAD].alive = FALSE;
  2880.                     worm[thissy - FIRSTHEAD].victor = player;
  2881.                 } else
  2882.                 {   effect(FXUSEARMOUR);
  2883.                     protector[player][thisprot].visible = FALSE;
  2884.             }    }
  2885.             else // protector is over worm's own head; caused by ramming
  2886.                 protector[player][thisprot].visible = FALSE;
  2887.         } else if (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2888.         {   if (player == thissy - FIRSTTAIL || worm[player].mode == TONGUE)
  2889.                 protector[player][thisprot].visible = FALSE;
  2890.         } else if (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2891.         {   protector[player][thisprot].alive = FALSE;
  2892.             for (which = 0; which <= PROTECTORS; which++)
  2893.             if (protector[thissy - FIRSTPROTECTOR][which].alive && protector[thissy - FIRSTPROTECTOR][which].x == x && protector[thissy - FIRSTPROTECTOR][which].y == y)
  2894.             {   protector[thissy - FIRSTPROTECTOR][which].alive = FALSE;
  2895.                 break;
  2896.             }
  2897.             draw(x, y, EMPTY);
  2898.             field[x][y] = EMPTY;
  2899.         } else if (thissy == STONE || thissy == WOOD)
  2900.             protector[player][thisprot].visible = FALSE;
  2901.         else if (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2902.         {   if (player != thissy - FIRSTMISSILE)
  2903.             {   effect(FXUSEPROTECTOR);
  2904.                 stopfx(missile[thissy - FIRSTMISSILE].receipt);
  2905.                 missile[thissy - FIRSTMISSILE].alive = FALSE;
  2906.             } else protector[player][thisprot].visible = FALSE;
  2907.         } else if (thissy == TELEPORT)
  2908.         {   protector[player][thisprot].visible = FALSE;
  2909.             score += TELPOINT;
  2910.         } else if (thissy == KILLER)
  2911.         {   effect(FXUSEPROTECTOR);
  2912.             effect(FXKILLERDEATH);
  2913.             which = whichkiller(x, y);
  2914.             protector[player][thisprot].last = BONUS;
  2915.             killer[which].alive = FALSE;
  2916.             score += KILLKILLER;
  2917.             if (worm[player].bias)
  2918.             {   worm[player].lives += KILLERBLOOD;
  2919.                 stat(player, LIVESLINE);
  2920.     }   }   }
  2921.     if (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2922.     {    wormletter(player, thissy);
  2923.         putletter(player);
  2924.     } else if (thissy <= LASTOBJECT)
  2925.     {   score += object[thissy].score;
  2926.         if (thissy != SLAYER && thissy != BOMB && thissy != MISSILE && thissy != NITRO && thissy != POWER && thissy != AMMO)
  2927.             effect(FXGETOBJECT);
  2928.         switch(thissy)
  2929.         {
  2930.         case BONUS:
  2931.             if (!worm[player].bias)
  2932.                 thisletter = rand() % (LETTERS + 1);
  2933.             else
  2934.             {    complete = TRUE;
  2935.                 for (which = 0; which <= LETTERS; which++)
  2936.                     if (!letters[player][which])
  2937.                     {    complete = FALSE;
  2938.                         do thisletter = rand() % (LETTERS + 1);
  2939.                         while (letters[player][thisletter]);
  2940.                         break;
  2941.                     }
  2942.                 if (complete)
  2943.                     thisletter = rand() % (LETTERS + 1);
  2944.             }
  2945.             letters[player][thisletter] = TRUE;
  2946.             drawletter(player, FIRSTLETTER + thisletter, NORMAL);
  2947.             break;
  2948.         case AMMO:
  2949.             effect(FXGETAMMO);
  2950.             worm[player].ammo += (rand() % AMMOMAX) + 1;
  2951.             stat(player, AMMOLINE);
  2952.             break;
  2953.         case ARMOUR:
  2954.             /* FXUSEDRILL sample will automatically stop, because
  2955.             a square with ARMOUR is not a square with TAIL. */
  2956.  
  2957.             worm[player].armour += MODEADD + (rand() % MODERAND);
  2958.             worm[player].mode = ARMOUR;
  2959.             stat(player, ARMOURLINE);
  2960.             break;
  2961.         case TONGUE:
  2962.             worm[player].tongue += MODEADD + (rand() % MODERAND);
  2963.             worm[player].mode = TONGUE;
  2964.             stat(player, TONGUELINE);
  2965.             worm[player].last = FIRSTTAIL + player;
  2966.             break;
  2967.         case NITRO:
  2968.             effect(FXGETNITRO);
  2969.             worm[player].nitro = TRUE;
  2970.             stat(player, SPEEDLINE);
  2971.             break;
  2972.         case BOMB:
  2973.             flag = FALSE;
  2974.             which = whichtimebomb(x, y);
  2975.             if (which != -1)
  2976.             {   flag = TRUE;
  2977.                 if (creature == HEAD)
  2978.                 {   // push timebomb
  2979.  
  2980.                     if (valid(x + worm[player].deltax, y + worm[player].deltay))
  2981.                     {   ithis = field[x + worm[player].deltax][y + worm[player].deltay];
  2982.                         if (ithis == TELEPORT)
  2983.                             score += BOMBOVEREDGE;
  2984.                         else if (ithis == SKULL)
  2985.                         {    effect(FXGETSKULL);
  2986.                             score += SKULLPOINT;
  2987.                         } else if (ithis <= LASTEMPTY)
  2988.                         {   if (ithis <= LASTOBJECT)
  2989.                             {   score += object[thissy].score;
  2990.                                 if (ithis == BOMB)
  2991.                                 {   iwhich = whichtimebomb(x + worm[player].deltax, y + worm[player].deltay);
  2992.                                     if (iwhich != -1)
  2993.                                         timebomb[iwhich].alive = FALSE;
  2994.                             }   }                                        
  2995.                             timebomb[which].x += worm[player].deltax;
  2996.                             timebomb[which].y += worm[player].deltay;
  2997.                             field[timebomb[which].x][timebomb[which].y] = BOMB;
  2998.                             draw(timebomb[which].x, timebomb[which].y, ZERO + timebomb[which].time);
  2999.                         } else flag = FALSE;
  3000.                     } else score += BOMBOVEREDGE;
  3001.                 } else protector[player][thisprot].visible = FALSE;
  3002.             }
  3003.             if (!flag)
  3004.             {   if (worm[player].mode == NULL)
  3005.                     draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3006.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3007.                 bombblast(HEAD, player, worm[player].x, worm[player].y);
  3008.             }
  3009.             break;
  3010.         case POWER:
  3011.             effect(FXGETPOWERUP);
  3012.             if (worm[player].power < POWERLIMIT)
  3013.             {    worm[player].power += 2;
  3014.                 stat(player, POWERLINE);
  3015.             }
  3016.             break;
  3017.         case SLAYER:
  3018.             for (which = 0; which <= ORBS; which++)
  3019.                 if (orb[which].alive)
  3020.                 {   score += orb[which].score;
  3021.                     orb[which].explode = TRUE;
  3022.                     if (worm[player].bias)
  3023.                         worm[player].lives += ORBBLOOD;
  3024.                 }
  3025.             for (which = 0; which <= KILLERS; which++)
  3026.                 if (killer[which].alive)
  3027.                 {    effect(FXKILLERDEATH);
  3028.                     killer[which].alive = FALSE;
  3029.                     score += KILLKILLER;
  3030.                     if (worm[player].bias)
  3031.                         worm[player].lives += KILLERBLOOD;
  3032.                     field[killer[which].x][killer[which].y] = BONUS;
  3033.                     draw(killer[which].x, killer[which].y, BONUS);
  3034.                 }
  3035.             for (which = lo; which <= hi; which++)
  3036.                 if (player != which && worm[which].mode != ARMOUR)
  3037.                 {    worm[which].alive = FALSE;
  3038.                     worm[which].cause = SLAYER;
  3039.                     worm[which].victor = player;
  3040.                 }
  3041.             for (x = 0; x <= FIELDX; x++)
  3042.                 for (y = 0; y <= FIELDY; y++)
  3043.                     if (field[x][y] == SLIME)
  3044.                     {    draw(x, y, EMPTY);
  3045.                         field[x][y] = EMPTY;
  3046.                     }
  3047.             if (worm[player].bias)
  3048.                 stat(player, LIVESLINE);
  3049.             break;
  3050.         case PROTECTOR:
  3051.             done = FALSE;
  3052.             for (which = 0; which <= PROTECTORS; which++)
  3053.                 if (!protector[player][which].alive && !done)
  3054.                 {    do
  3055.                     {    protector[player][which].relx = ((rand() % 2) * 2) - 1;
  3056.                         protector[player][which].rely = ((rand() % 2) * 2) - 1;
  3057.                         for (iwhich = 0; iwhich <= PROTECTORS; iwhich++)
  3058.                             if (which == NOSE || !protector[player][iwhich].alive || protector[player][iwhich].x != xwrap(worm[player].x + protector[player][which].relx) || protector[player][iwhich].y != ywrap(worm[player].y + protector[player][which].rely))
  3059.                             {    effect(FXPROTECTORBORN);
  3060.                                 done = TRUE;
  3061.                                 protector[player][which].alive = TRUE;
  3062.                                 protector[player][which].visible = FALSE;
  3063.                                 protector[player][which].last = EMPTY;
  3064.                                 if (which == NOSE)
  3065.                                     worm[player].position = -1;
  3066.                             }
  3067.                     } while (!done);
  3068.                 }
  3069.             break;
  3070.         case MISSILE:
  3071.             if (!missile[player].alive)
  3072.             {   missile[player].receipt = effect(FXMISSILEACTIVE);
  3073.                 missile[player].alive = TRUE;
  3074.                 missile[player].x = worm[player].x;
  3075.                 missile[player].y = worm[player].y;
  3076.                 missile[player].moved = FALSE;
  3077.             }
  3078.             break;
  3079.         case LIFE:
  3080.             worm[player].lives += (rand() % LIFEMAX) + 1;
  3081.             stat(player, LIVESLINE);
  3082.             break;
  3083.         case MULTIPLIER:
  3084.             if (worm[player].multi < MULTILIMIT)
  3085.                 worm[player].multi *= 2;
  3086.             break;
  3087.         case BIAS:
  3088.             worm[player].bias += MODEADD + (rand() % MODERAND);
  3089.             stat(player, BIASLINE);
  3090.             break;
  3091.         case ICE:
  3092.             worm[player].ice += ICEADD + (rand() % ICERAND);
  3093.             ice = player;
  3094.             break;
  3095.         case GROWER:
  3096.             effect(FXGETGROWER);
  3097.             for (x = 0; x <= FIELDX; x++)
  3098.                 for (y = 0; y <= FIELDY; y++)
  3099.                     if (field[x][y] == GOLD)
  3100.                     {    for (xx = x - 1; xx <= x + 1; xx++)
  3101.                             for (yy = y - 1; yy <= y + 1; yy++)
  3102.                                 if (valid(xx, yy))
  3103.                                     if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPSILVER)
  3104.                                         field[xx][yy] = TEMPGOLD;
  3105.                                     else if (field[xx][yy] == SILVER)
  3106.                                         field[xx][yy] = WASSILVER;
  3107.                     }
  3108.                     else if (field[x][y] == SILVER || field[x][y] == WASSILVER)
  3109.                         for (xx = x - 1; xx <= x + 1; xx++)
  3110.                             for (yy = y - 1; yy <= y + 1; yy++)
  3111.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY)
  3112.                                     field[xx][yy] = TEMPSILVER;
  3113.             for (x = 0; x <= FIELDX; x++)
  3114.                 for (y = 0; y <= FIELDY; y++)
  3115.                     if (field[x][y] == TEMPGOLD || field[x][y] == WASSILVER)
  3116.                     {    field[x][y] = GOLD;
  3117.                         draw(x, y, GOLD);
  3118.                     }
  3119.                     else if (field[x][y] == TEMPSILVER)
  3120.                     {    field[x][y] = SILVER;
  3121.                         draw(x, y, SILVER);
  3122.                     }
  3123.             break;
  3124.         case TREASURE:
  3125.             treasurer = player;
  3126.             if (level)
  3127.             {    say((STRPTR) "Treasure!", worm[treasurer].colour);
  3128.                 secondsperlevel = 0;
  3129.             }
  3130.             secondsperlevel += TREASUREADD + (rand() % TREASURERAND);
  3131.             if (level)
  3132.             {    stat(player, SCORELINE);
  3133.                 reallevel = level;
  3134.                 level = 0;
  3135.                 newlevel(player);
  3136.             }
  3137.             break;
  3138.         case AFFIXER:
  3139.             worm[player].affixer = TRUE;
  3140.             break;
  3141.         case SWITCHER:
  3142.             if (lo != hi)
  3143.                 for (x = 0; x <= FIELDX; x++)
  3144.                     for (y = 0; y <= FIELDY; y++)
  3145.                         if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL && field[x][y] != FIRSTTAIL + player)
  3146.                         {    field[x][y] = FIRSTTAIL + player;
  3147.                             draw(x, y, FIRSTTAIL + player);
  3148.                         }
  3149.             break;
  3150.         case HEALER:
  3151.             if (worm[player].lives < 100)
  3152.                 worm[player].lives = 100;
  3153.             else worm[player].lives = LIFEMAX;
  3154.             stat(player, LIVESLINE);
  3155.             break;
  3156.         default:
  3157.             break;
  3158.     }    }
  3159.     else
  3160.     {   switch (thissy)
  3161.         {
  3162.         case EMPTY:
  3163.             score += EMPTYPOINT;
  3164.             break;
  3165.         case SILVER:
  3166.             score += SILVERPOINT;
  3167.             break;
  3168.         case GOLD:
  3169.             score += GOLDPOINT;
  3170.             break;
  3171.         case ORB:
  3172.             iwhich = whichorb(x, y);
  3173.             if (worm[player].mode == ARMOUR || creature == PROTECTOR)
  3174.             {   if (creature == HEAD)
  3175.                     effect(FXUSEARMOUR);
  3176.                 else effect(FXUSEPROTECTOR);
  3177.                 effect(FXORBDEATH);
  3178.                 score += orb[iwhich].score;
  3179.                 orb[iwhich].alive = FALSE;
  3180.                 if (worm[player].bias)
  3181.                 {   worm[player].lives += ORBBLOOD;
  3182.                     stat(player, LIVESLINE);
  3183.             }   }
  3184.             else
  3185.             {   if (orb[iwhich].mode == ARMOUR)
  3186.                 {   effect(FXUSEARMOUR);
  3187.                     orb[iwhich].score += KILLWORM * orb[iwhich].multi;
  3188.                 } else orb[iwhich].alive = FALSE;
  3189.                 worm[player].cause = ORB;
  3190.                 worm[player].victor = -1;
  3191.                 worm[player].alive = FALSE;
  3192.             }
  3193.             break;
  3194.         case FRAGMENT:
  3195.             whichfrag(x, y, &which, &iwhich);
  3196.             if (creature == HEAD)
  3197.             {    if (worm[player].mode != ARMOUR)
  3198.                 {   worm[player].cause = FRAGMENT;
  3199.                     worm[player].victor = -1;
  3200.                     worm[player].alive = FALSE;
  3201.                     frag[which][iwhich].alive = FALSE;
  3202.                 } else
  3203.                 {    effect(FXUSEARMOUR);
  3204.                     reflect(which, iwhich);
  3205.             }    }
  3206.             else
  3207.             {    effect(FXUSEPROTECTOR);
  3208.                 reflect(which, iwhich);
  3209.             }
  3210.             break;
  3211.         case SKULL:
  3212.             effect(FXGETSKULL);
  3213.             score += SKULLPOINT;
  3214.             for (which = lo; which <= hi; which++)
  3215.             {    if (worm[which].alive == FALSE && worm[which].x == worm[player].x && worm[which].y == worm[player].y)
  3216.                     iwhich = which;
  3217.             }
  3218.             worm[player].bias    += worm[iwhich].bias;
  3219.             if (worm[player].bias > 0)
  3220.             {    stat(player, BIASLINE);
  3221.                 worm[iwhich].bias = 0;
  3222.                 stat(iwhich, BIASLINE);
  3223.             }
  3224.             worm[player].multi    *= worm[iwhich].multi;
  3225.             if (worm[player].multi > 1)
  3226.             {    if (worm[player].multi > MULTILIMIT)
  3227.                     worm[player].multi = MULTILIMIT;
  3228.             }
  3229.             worm[player].power    += worm[iwhich].power;
  3230.             if (worm[player].power > 1)
  3231.             {    if (worm[player].power > POWERLIMIT)
  3232.                     worm[player].power = POWERLIMIT;
  3233.                 stat(player, POWERLINE);
  3234.                 worm[iwhich].power = 0;
  3235.                 stat(iwhich, POWERLINE);
  3236.             }
  3237.             worm[player].ammo    += worm[iwhich].ammo;
  3238.             if (worm[player].ammo > 0)
  3239.             {    stat(player, AMMOLINE);
  3240.                 worm[iwhich].ammo = 0;
  3241.                 stat(iwhich, AMMOLINE);
  3242.             }
  3243.             worm[player].armour    += worm[iwhich].armour;
  3244.             if (worm[player].armour > 0)
  3245.             {    stat(player, ARMOURLINE);
  3246.                 worm[iwhich].armour = 0;
  3247.                 stat(iwhich, ARMOURLINE);
  3248.             }
  3249.             worm[player].tongue    += worm[iwhich].tongue;
  3250.             if (worm[player].tongue > 0)
  3251.             {    stat(player, TONGUELINE);
  3252.                 worm[iwhich].tongue = 0;
  3253.                 stat(iwhich, TONGUELINE);
  3254.             }
  3255.             if (worm[player].armour > 0 || worm[player].tongue > 0)
  3256.             {    if (worm[player].armour >= worm[player].tongue)
  3257.                     worm[player].mode = ARMOUR;
  3258.                 else worm[player].mode = TONGUE;
  3259.             }
  3260.             if (worm[iwhich].nitro)
  3261.             {    worm[player].nitro = TRUE;
  3262.                 stat(player, SPEEDLINE);
  3263.                 worm[iwhich].nitro = FALSE;
  3264.                 worm[iwhich].speed = NORMAL;
  3265.                 stat(iwhich, SPEEDLINE);
  3266.             }
  3267.             for (which = 0; which <= LETTERS; which++)
  3268.                 if (letters[iwhich][which])
  3269.                 {    blitmode(BLACK);
  3270.                     drawletter(iwhich, FIRSTLETTER + which, BLACK);
  3271.                     blitmode(NORMAL);
  3272.                     if (!letters[player][which])
  3273.                     {    letters[player][which] = TRUE;
  3274.                         drawletter(player, FIRSTLETTER + which, NORMAL);
  3275.                 }    }
  3276.             break;
  3277.         default:
  3278.             break;
  3279.     }    }    
  3280.     if (creature == HEAD)
  3281.     // it is important that HEAD is done before PROTECTORs
  3282.     {   if (worm[player].tonguereceipt && (thissy < FIRSTTAIL || thissy > LASTTAIL))
  3283.         {    stopfx(worm[player].tonguereceipt);
  3284.             worm[player].tonguereceipt = 0L;
  3285.         }
  3286.         field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
  3287.         if (worm[player].alive)
  3288.         {    switch (worm[player].mode)
  3289.             {
  3290.             case NULL:
  3291.                 draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3292.                 break;
  3293.             case TONGUE:
  3294.                 if (worm[player].tongue < 10 && (r / VERYSLOW) % 2 == 0)
  3295.                     blitmode(WHITE);
  3296.                 else
  3297.                     blitmode(NORMAL);
  3298.                 draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3299.                 blitmode(NORMAL);
  3300.                 break;
  3301.             case ARMOUR:
  3302.                 if (worm[player].armour < 10 && (r / VERYSLOW) % 2 == 0)
  3303.                     blitmode(WHITE);
  3304.                 else
  3305.                     blitmode(NORMAL);
  3306.                 draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3307.                 blitmode(NORMAL);
  3308.                 break;
  3309.             default:
  3310.                 break;
  3311.         }    }
  3312.         else draw(worm[player].x, worm[player].y, SKULL);
  3313.     } else // assumes creature == PROTECTOR
  3314.         if (protector[player][thisprot].alive && protector[player][thisprot].visible)
  3315.         {   field[x][y] = FIRSTPROTECTOR + player;
  3316.             draw(x, y, FIRSTPROTECTOR + player);
  3317.         }
  3318.     while (++thisprot <= PROTECTORS)
  3319.         if (protector[player][thisprot].alive && valid(protector[player][thisprot].x, protector[player][thisprot].y))
  3320.             break;
  3321.     if (thisprot > PROTECTORS)
  3322.         creature = NULL;
  3323.     else creature = PROTECTOR;
  3324. }
  3325. wormscore(player, score);
  3326. }
  3327.  
  3328. void wormscore(SBYTE player, LONG score)
  3329. {   worm[player].score += score * worm[player].multi;
  3330.     stat(player, SCORELINE);
  3331. }
  3332.  
  3333. SWORD wsign(SWORD value)
  3334. {    if (value < 0)
  3335.         return (-1);
  3336.     else if (value > 0)
  3337.         return (1);
  3338.     else
  3339.         return (0);
  3340. }
  3341.  
  3342. SWORD xpixeltosquare(SWORD x)
  3343. {    x = (x - STARTXPIXEL) / SQUAREX;
  3344.     if (x < 0)
  3345.         x--;
  3346.     return (x);
  3347. }
  3348. SWORD ypixeltosquare(SWORD y)
  3349. {    y = (y - STARTYPIXEL) / SQUAREY;
  3350.     if (y < 0)
  3351.         y--;
  3352.     return (y);
  3353. }
  3354.  
  3355. SBYTE xwrap(SBYTE x)
  3356. {    if (x < 0)
  3357.         x += FIELDX + 1;
  3358.     else if (x > FIELDX)
  3359.         x -= FIELDX + 1;
  3360.     return(x);
  3361. }
  3362. SBYTE ywrap(SBYTE y)
  3363. {    if (y < 0)
  3364.         y += FIELDY + 1;
  3365.     else if (y > FIELDY)
  3366.         y -= FIELDY + 1;
  3367.     return(y);
  3368. }
  3369.  
  3370. // Must have blank line at EOF.
  3371.